Author: Jim Wigginton (terrafrost@php.net)
Ejemplo n.º 1
0
 /**
  * Break a public or private key down into its constituent components
  *
  * @access public
  * @param string $key
  * @param string $password optional
  * @return array
  */
 static function load($key, $password = '')
 {
     if (!is_string($key)) {
         return false;
     }
     $parts = explode(' ', $key, 3);
     $key = isset($parts[1]) ? Base64::decode($parts[1]) : Base64::decode($parts[0]);
     if ($key === false) {
         return false;
     }
     $comment = isset($parts[2]) ? $parts[2] : false;
     if (substr($key, 0, 11) != "ssh-rsa") {
         return false;
     }
     Strings::shift($key, 11);
     if (strlen($key) <= 4) {
         return false;
     }
     extract(unpack('Nlength', Strings::shift($key, 4)));
     if (strlen($key) <= $length) {
         return false;
     }
     $publicExponent = new BigInteger(Strings::shift($key, $length), -256);
     if (strlen($key) <= 4) {
         return false;
     }
     extract(unpack('Nlength', Strings::shift($key, 4)));
     if (strlen($key) != $length) {
         return false;
     }
     $modulus = new BigInteger(Strings::shift($key, $length), -256);
     return array('isPublicKey' => true, 'modulus' => $modulus, 'publicExponent' => $publicExponent, 'comment' => $comment);
 }
Ejemplo n.º 2
0
 /**
  * Break a public or private key down into its constituent components
  *
  * @access public
  * @param string $key
  * @param string $password optional
  * @return array
  */
 static function load($key, $password = '')
 {
     if (!is_string($key)) {
         return false;
     }
     static $one;
     if (!isset($one)) {
         $one = new BigInteger(1);
     }
     if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
         $data = preg_split('#[\\r\\n]+#', $key);
         $data = array_splice($data, 2, -1);
         $data = implode('', $data);
         $components = OpenSSH::load($data);
         if ($components === false) {
             return false;
         }
         if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
             return false;
         }
         $components['comment'] = str_replace(array('\\\\', '\\"'), array('\\', '"'), $matches[1]);
         return $components;
     }
     $components = array('isPublicKey' => false);
     $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]));
     $components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
     $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', Strings::shift($public, 4)));
     $components['publicExponent'] = new BigInteger(Strings::shift($public, $length), -256);
     extract(unpack('Nlength', Strings::shift($public, 4)));
     $components['modulus'] = new BigInteger(Strings::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':
             $symkey = static::generateSymmetricKey($password, 32);
             $crypto = new AES(AES::MODE_CBC);
     }
     if ($encryption != 'none') {
         $crypto->setKey($symkey);
         $crypto->setIV(str_repeat("", $crypto->getBlockLength() >> 3));
         $crypto->disablePadding();
         $private = $crypto->decrypt($private);
     }
     extract(unpack('Nlength', Strings::shift($private, 4)));
     if (strlen($private) < $length) {
         return false;
     }
     $components['privateExponent'] = new BigInteger(Strings::shift($private, $length), -256);
     extract(unpack('Nlength', Strings::shift($private, 4)));
     if (strlen($private) < $length) {
         return false;
     }
     $components['primes'] = array(1 => new BigInteger(Strings::shift($private, $length), -256));
     extract(unpack('Nlength', Strings::shift($private, 4)));
     if (strlen($private) < $length) {
         return false;
     }
     $components['primes'][] = new BigInteger(Strings::shift($private, $length), -256);
     $temp = $components['primes'][1]->subtract($one);
     $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
     $temp = $components['primes'][2]->subtract($one);
     $components['exponents'][] = $components['publicExponent']->modInverse($temp);
     extract(unpack('Nlength', Strings::shift($private, 4)));
     if (strlen($private) < $length) {
         return false;
     }
     $components['coefficients'] = array(2 => new BigInteger(Strings::shift($private, $length), -256));
     return $components;
 }
Ejemplo n.º 3
0
 /**
  * Break a public or private key down into its constituent components
  *
  * @access public
  * @param string $key
  * @param string $password optional
  * @return array
  */
 static function load($key, $password = '')
 {
     if (!is_string($key)) {
         return false;
     }
     $components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false);
     /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
                "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
                protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
                two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:
     
                http://tools.ietf.org/html/rfc1421#section-4.6.1.1
                http://tools.ietf.org/html/rfc1421#section-4.6.1.3
     
                DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
                DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
                function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
                own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
                implementation are part of the standard, as well.
     
                * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
     if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
         $iv = Hex::decode(trim($matches[2]));
         // remove the Proc-Type / DEK-Info sections as they're no longer needed
         $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
         $ciphertext = self::_extractBER($key);
         if ($ciphertext === false) {
             $ciphertext = $key;
         }
         $crypto = self::getEncryptionObject($matches[1]);
         $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
         $crypto->setIV($iv);
         $key = $crypto->decrypt($ciphertext);
         if ($key === false) {
             return false;
         }
     } else {
         if (self::$format != self::MODE_DER) {
             $decoded = self::_extractBER($key);
             if ($decoded !== false) {
                 $key = $decoded;
             } elseif (self::$format == self::MODE_PEM) {
                 return false;
             }
         }
     }
     if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
         return false;
     }
     if (ASN1::decodeLength($key) != strlen($key)) {
         return false;
     }
     $tag = ord(Strings::shift($key));
     /* intended for keys for which OpenSSL's asn1parse returns the following:
     
                 0:d=0  hl=4 l= 631 cons: SEQUENCE
                 4:d=1  hl=2 l=   1 prim:  INTEGER           :00
                 7:d=1  hl=2 l=  13 cons:  SEQUENCE
                 9:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
                20:d=2  hl=2 l=   0 prim:   NULL
                22:d=1  hl=4 l= 609 prim:  OCTET STRING
     
                ie. PKCS8 keys */
     if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "0") {
         Strings::shift($key, 3);
         $tag = self::ASN1_SEQUENCE;
     }
     if ($tag == self::ASN1_SEQUENCE) {
         $temp = Strings::shift($key, ASN1::decodeLength($key));
         if (ord(Strings::shift($temp)) != self::ASN1_OBJECT) {
             return false;
         }
         $length = ASN1::decodeLength($temp);
         switch (Strings::shift($temp, $length)) {
             case "*†H†÷\r":
                 // rsaEncryption
                 break;
             case "*†H†÷\r":
                 // pbeWithMD5AndDES-CBC
                 /*
                    PBEParameter ::= SEQUENCE {
                        salt OCTET STRING (SIZE(8)),
                        iterationCount INTEGER }
                 */
                 if (ord(Strings::shift($temp)) != self::ASN1_SEQUENCE) {
                     return false;
                 }
                 if (ASN1::decodeLength($temp) != strlen($temp)) {
                     return false;
                 }
                 Strings::shift($temp);
                 // assume it's an octet string
                 $salt = Strings::shift($temp, ASN1::decodeLength($temp));
                 if (ord(Strings::shift($temp)) != self::ASN1_INTEGER) {
                     return false;
                 }
                 ASN1::decodeLength($temp);
                 list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
                 Strings::shift($key);
                 // assume it's an octet string
                 $length = ASN1::decodeLength($key);
                 if (strlen($key) != $length) {
                     return false;
                 }
                 $crypto = new DES(DES::MODE_CBC);
                 $crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
                 $key = $crypto->decrypt($key);
                 if ($key === false) {
                     return false;
                 }
                 return self::load($key);
             default:
                 return false;
         }
         /* intended for keys for which OpenSSL's asn1parse returns the following:
         
                         0:d=0  hl=4 l= 290 cons: SEQUENCE
                         4:d=1  hl=2 l=  13 cons:  SEQUENCE
                         6:d=2  hl=2 l=   9 prim:   OBJECT            :rsaEncryption
                        17:d=2  hl=2 l=   0 prim:   NULL
                        19:d=1  hl=4 l= 271 prim:  BIT STRING */
         $tag = ord(Strings::shift($key));
         // skip over the BIT STRING / OCTET STRING tag
         ASN1::decodeLength($key);
         // skip over the BIT STRING / OCTET STRING length
         // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
         //  unused bits in the final subsequent octet. The number shall be in the range zero to seven."
         //  -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
         if ($tag == self::ASN1_BITSTRING) {
             Strings::shift($key);
         }
         if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
             return false;
         }
         if (ASN1::decodeLength($key) != strlen($key)) {
             return false;
         }
         $tag = ord(Strings::shift($key));
     }
     if ($tag != self::ASN1_INTEGER) {
         return false;
     }
     $length = ASN1::decodeLength($key);
     $temp = Strings::shift($key, $length);
     if (strlen($temp) != 1 || ord($temp) > 2) {
         $components['modulus'] = new BigInteger($temp, 256);
         Strings::shift($key);
         // skip over self::ASN1_INTEGER
         $length = ASN1::decodeLength($key);
         $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(Strings::shift($key, $length), 256);
         return $components;
     }
     if (ord(Strings::shift($key)) != self::ASN1_INTEGER) {
         return false;
     }
     $length = ASN1::decodeLength($key);
     $components['modulus'] = new BigInteger(Strings::shift($key, $length), 256);
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['publicExponent'] = new BigInteger(Strings::shift($key, $length), 256);
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['privateExponent'] = new BigInteger(Strings::shift($key, $length), 256);
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['primes'] = array(1 => new BigInteger(Strings::shift($key, $length), 256));
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['primes'][] = new BigInteger(Strings::shift($key, $length), 256);
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['exponents'] = array(1 => new BigInteger(Strings::shift($key, $length), 256));
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256);
     Strings::shift($key);
     $length = ASN1::decodeLength($key);
     $components['coefficients'] = array(2 => new BigInteger(Strings::shift($key, $length), 256));
     if (!empty($key)) {
         if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
             return false;
         }
         ASN1::decodeLength($key);
         while (!empty($key)) {
             if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
                 return false;
             }
             ASN1::decodeLength($key);
             $key = substr($key, 1);
             $length = ASN1::decodeLength($key);
             $components['primes'][] = new BigInteger(Strings::shift($key, $length), 256);
             Strings::shift($key);
             $length = ASN1::decodeLength($key);
             $components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256);
             Strings::shift($key);
             $length = ASN1::decodeLength($key);
             $components['coefficients'][] = new BigInteger(Strings::shift($key, $length), 256);
         }
     }
     return $components;
 }
Ejemplo n.º 4
0
 /**
  * Returns the server public host key.
  *
  * Caching this the first time you connect to a server and checking the result on subsequent connections
  * is recommended.  Returns false if the server signature is not signed correctly with the public host key.
  *
  * @return mixed
  * @throws \RuntimeException on badly formatted keys
  * @throws \phpseclib\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format
  * @access public
  */
 function getServerPublicHostKey()
 {
     if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
         if (!$this->_connect()) {
             return false;
         }
     }
     $signature = $this->signature;
     $server_public_host_key = $this->server_public_host_key;
     if (strlen($server_public_host_key) < 4) {
         return false;
     }
     extract(unpack('Nlength', Strings::shift($server_public_host_key, 4)));
     Strings::shift($server_public_host_key, $length);
     if ($this->signature_validated) {
         return $this->bitmap ? $this->signature_format . ' ' . Base64::encode($this->server_public_host_key) : false;
     }
     $this->signature_validated = true;
     switch ($this->signature_format) {
         case 'ssh-dss':
             $zero = new BigInteger();
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $p = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $q = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $g = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $y = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
             /* The value for 'dss_signature_blob' is encoded as a string containing
                r, followed by s (which are 160-bit integers, without lengths or
                padding, unsigned, and in network byte order). */
             $temp = unpack('Nlength', Strings::shift($signature, 4));
             if ($temp['length'] != 40) {
                 $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                 throw new \RuntimeException('Invalid signature');
             }
             $r = new BigInteger(Strings::shift($signature, 20), 256);
             $s = new BigInteger(Strings::shift($signature, 20), 256);
             switch (true) {
                 case $r->equals($zero):
                 case $r->compare($q) >= 0:
                 case $s->equals($zero):
                 case $s->compare($q) >= 0:
                     $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                     throw new \RuntimeException('Invalid signature');
             }
             $w = $s->modInverse($q);
             $u1 = $w->multiply(new 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');
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             break;
         case 'ssh-rsa':
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $e = new BigInteger(Strings::shift($server_public_host_key, $temp['length']), -256);
             if (strlen($server_public_host_key) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($server_public_host_key, 4));
             $rawN = Strings::shift($server_public_host_key, $temp['length']);
             $n = new BigInteger($rawN, -256);
             $nLength = strlen(ltrim($rawN, ""));
             /*
             if (strlen($signature) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($signature, 4));
             $signature = Strings::shift($signature, $temp['length']);
             
             $rsa = new RSA();
             $rsa->load(array('e' => $e, 'n' => $n), 'raw');
             $rsa->setHash('sha1');
             if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) {
                 //user_error('Bad server signature');
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             */
             if (strlen($signature) < 4) {
                 return false;
             }
             $temp = unpack('Nlength', Strings::shift($signature, 4));
             $s = new BigInteger(Strings::shift($signature, $temp['length']), 256);
             // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
             // following URL:
             // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
             // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
             if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
                 $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                 throw new \RuntimeException('Invalid signature');
             }
             $s = $s->modPow($e, $n);
             $s = $s->toBytes();
             $h = pack('N4H*', 0x302130, 0x906052b, 0xe03021a, 0x5000414, sha1($this->exchange_hash));
             $h = chr(0x1) . str_repeat(chr(0xff), $nLength - 2 - strlen($h)) . $h;
             if ($s != $h) {
                 //user_error('Bad server signature');
                 return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             }
             break;
         default:
             $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
             throw new NoSupportedAlgorithmsException('Unsupported signature format');
     }
     return $this->signature_format . ' ' . Base64::encode($this->server_public_host_key);
 }
Ejemplo n.º 5
0
 /**
  * Break a public or private key down into its constituent components
  *
  * @access public
  * @param string $key
  * @param string $password optional
  * @return array
  */
 static function load($key, $password = '')
 {
     if (!is_string($key)) {
         return false;
     }
     $key = Base64::decode($key);
     if (!is_string($key) || strlen($key) < 20) {
         return false;
     }
     // PUBLICKEYSTRUC  publickeystruc
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
     extract(unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8)));
     switch (ord($type)) {
         case self::PUBLICKEYBLOB:
         case self::PUBLICKEYBLOBEX:
             $publickey = true;
             break;
         case self::PRIVATEKEYBLOB:
             $publickey = false;
             break;
         default:
             return false;
     }
     $components = array('isPublicKey' => $publickey);
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
     switch ($algo) {
         case self::CALG_RSA_KEYX:
         case self::CALG_RSA_SIGN:
             break;
         default:
             return false;
     }
     // RSAPUBKEY rsapubkey
     // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
     // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
     extract(unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12)));
     switch ($magic) {
         case self::RSA2:
             $components['isPublicKey'] = false;
         case self::RSA1:
             break;
         default:
             return false;
     }
     $baseLength = $bitlen / 16;
     if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
         return false;
     }
     $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
     // BYTE modulus[rsapubkey.bitlen/8]
     $components['modulus'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256);
     if ($publickey) {
         return $components;
     }
     $components['isPublicKey'] = false;
     // BYTE prime1[rsapubkey.bitlen/16]
     $components['primes'] = array(1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256));
     // BYTE prime2[rsapubkey.bitlen/16]
     $components['primes'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256);
     // BYTE exponent1[rsapubkey.bitlen/16]
     $components['exponents'] = array(1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256));
     // BYTE exponent2[rsapubkey.bitlen/16]
     $components['exponents'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256);
     // BYTE coefficient[rsapubkey.bitlen/16]
     $components['coefficients'] = array(2 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256));
     if (isset($components['privateExponent'])) {
         $components['publicExponent'] = $components['privateExponent'];
     }
     // BYTE privateExponent[rsapubkey.bitlen/8]
     $components['privateExponent'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256);
     return $components;
 }
Ejemplo n.º 6
0
 /**
  * Receives a packet from an SSH server
  *
  * @return string
  * @throws \UnexpectedValueException on receipt of an unexpected packet
  * @access private
  */
 function _receive()
 {
     switch ($this->mode) {
         case self::MODE_SSH2:
             return $this->ssh->_get_channel_packet(SSH2::CHANNEL_EXEC, true);
         case self::MODE_SSH1:
             if (!$this->ssh->bitmap) {
                 return false;
             }
             while (true) {
                 $response = $this->ssh->_get_binary_packet();
                 switch ($response[SSH1::RESPONSE_TYPE]) {
                     case NET_SSH1_SMSG_STDOUT_DATA:
                         if (strlen($response[SSH1::RESPONSE_DATA]) < 4) {
                             return false;
                         }
                         extract(unpack('Nlength', $response[SSH1::RESPONSE_DATA]));
                         return Strings::shift($response[SSH1::RESPONSE_DATA], $length);
                     case NET_SSH1_SMSG_STDERR_DATA:
                         break;
                     case NET_SSH1_SMSG_EXITSTATUS:
                         $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION));
                         fclose($this->ssh->fsock);
                         $this->ssh->bitmap = 0;
                         return false;
                     default:
                         throw new \UnexpectedValueException('Unknown packet received');
                 }
             }
     }
 }
Ejemplo n.º 7
0
 /**
  * RSASSA-PKCS1-V1_5-VERIFY (relaxed matching)
  *
  * Per {@link http://tools.ietf.org/html/rfc3447#page-43 RFC3447#page-43} PKCS1 v1.5
  * specified the use BER encoding rather than DER encoding that PKCS1 v2.0 specified.
  * This means that under rare conditions you can have a perfectly valid v1.5 signature
  * that fails to validate with _rsassa_pkcs1_v1_5_verify(). PKCS1 v2.1 also recommends
  * that if you're going to validate these types of signatures you "should indicate
  * whether the underlying BER encoding is a DER encoding and hence whether the signature
  * is valid with respect to the specification given in [PKCS1 v2.0+]". so if you do
  * $rsa->getLastPadding() and get RSA::PADDING_RELAXED_PKCS1 back instead of
  * RSA::PADDING_PKCS1... that means BER encoding was used.
  *
  * @access private
  * @param string $m
  * @param string $s
  * @return bool
  */
 function _rsassa_pkcs1_v1_5_relaxed_verify($m, $s)
 {
     // Length checking
     if (strlen($s) != $this->k) {
         return false;
     }
     // RSA verification
     $s = $this->_os2ip($s);
     $m2 = $this->_rsavp1($s);
     if ($m2 === false) {
         return false;
     }
     $em = $this->_i2osp($m2, $this->k);
     if ($em === false) {
         return false;
     }
     if (Strings::shift($em, 2) != "") {
         return false;
     }
     $em = ltrim($em, "ÿ");
     if (Strings::shift($em) != "") {
         return false;
     }
     $asn1 = new ASN1();
     $decoded = $asn1->decodeBER($em);
     if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) {
         return false;
     }
     $AlgorithmIdentifier = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER), 'parameters' => array('type' => ASN1::TYPE_ANY, 'optional' => true)));
     $DigestInfo = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('digestAlgorithm' => $AlgorithmIdentifier, 'digest' => array('type' => ASN1::TYPE_OCTET_STRING)));
     $oids = array('1.2.840.113549.2.2' => 'md2', '1.2.840.113549.2.4' => 'md4', '1.2.840.113549.2.5' => 'md5', '1.3.14.3.2.26' => 'sha1', '2.16.840.1.101.3.4.2.1' => 'sha256', '2.16.840.1.101.3.4.2.2' => 'sha384', '2.16.840.1.101.3.4.2.3' => 'sha512', '2.16.840.1.101.3.4.2.4' => 'sha224', '2.16.840.1.101.3.4.2.5' => 'sha512/224', '2.16.840.1.101.3.4.2.6' => 'sha512/256');
     $asn1->loadOIDs($oids);
     $decoded = $asn1->asn1map($decoded[0], $DigestInfo);
     if (!isset($decoded) || $decoded === false) {
         return false;
     }
     if (!in_array($decoded['digestAlgorithm']['algorithm'], $oids)) {
         return false;
     }
     $hash = new Hash($decoded['digestAlgorithm']['algorithm']);
     $em = $hash->hash($m);
     $em2 = Base64::decode($decoded['digest']);
     return $this->_equals($em, $em2);
 }
Ejemplo n.º 8
0
 /**
  * Receives SFTP Packets
  *
  * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
  *
  * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
  * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
  * messages containing one SFTP packet.
  *
  * @see self::_send_sftp_packet()
  * @return string
  * @access private
  */
 function _get_sftp_packet()
 {
     $this->curTimeout = false;
     $start = strtok(microtime(), ' ') + strtok('');
     // http://php.net/microtime#61838
     // SFTP packet length
     while (strlen($this->packet_buffer) < 4) {
         $temp = $this->_get_channel_packet(self::CHANNEL);
         if (is_bool($temp)) {
             $this->packet_type = false;
             $this->packet_buffer = '';
             return false;
         }
         $this->packet_buffer .= $temp;
     }
     if (strlen($this->packet_buffer) < 4) {
         return false;
     }
     extract(unpack('Nlength', Strings::shift($this->packet_buffer, 4)));
     $tempLength = $length;
     $tempLength -= strlen($this->packet_buffer);
     // SFTP packet type and data payload
     while ($tempLength > 0) {
         $temp = $this->_get_channel_packet(self::CHANNEL);
         if (is_bool($temp)) {
             $this->packet_type = false;
             $this->packet_buffer = '';
             return false;
         }
         $this->packet_buffer .= $temp;
         $tempLength -= strlen($temp);
     }
     $stop = strtok(microtime(), ' ') + strtok('');
     $this->packet_type = ord(Strings::shift($this->packet_buffer));
     if ($this->request_id !== false) {
         Strings::shift($this->packet_buffer, 4);
         // remove the request id
         $length -= 5;
         // account for the request id and the packet type
     } else {
         $length -= 1;
         // account for the packet type
     }
     $packet = Strings::shift($this->packet_buffer, $length);
     if (defined('NET_SFTP_LOGGING')) {
         $packet_type = '<- ' . $this->packet_types[$this->packet_type] . ' (' . round($stop - $start, 4) . 's)';
         if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
             echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
             flush();
             ob_flush();
         } else {
             $this->packet_type_log[] = $packet_type;
             if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
                 $this->packet_log[] = $packet;
             }
         }
     }
     return $packet;
 }
Ejemplo n.º 9
0
 /**
  * Pure-PHP implementation of SHA512
  *
  * @access private
  * @param string $m
  */
 static function _sha512($m, $hash)
 {
     static $k;
     if (!isset($k)) {
         // Initialize table of round constants
         // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
         $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 BigInteger($k[$i], 16);
         }
     }
     // Pre-processing
     $length = strlen($m);
     // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
     $m .= str_repeat(chr(0), 128 - ($length + 16 & 0x7f));
     $m[$length] = chr(0x80);
     // we don't support hashing strings 512MB long
     $m .= pack('N4', 0, 0, 0, $length << 3);
     // Process the message in successive 1024-bit chunks
     $chunks = str_split($m, 128);
     foreach ($chunks as $chunk) {
         $w = array();
         for ($i = 0; $i < 16; $i++) {
             $temp = new BigInteger(Strings::shift($chunk, 8), 256);
             $temp->setPrecision(64);
             $w[] = $temp;
         }
         // Extend the sixteen 32-bit words into eighty 32-bit words
         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] = clone $w[$i - 16];
             $w[$i] = $w[$i]->add($s0);
             $w[$i] = $w[$i]->add($w[$i - 7]);
             $w[$i] = $w[$i]->add($s1);
         }
         // Initialize hash value for this chunk
         $a = clone $hash[0];
         $b = clone $hash[1];
         $c = clone $hash[2];
         $d = clone $hash[3];
         $e = clone $hash[4];
         $f = clone $hash[5];
         $g = clone $hash[6];
         $h = clone $hash[7];
         // Main loop
         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 = clone $g;
             $g = clone $f;
             $f = clone $e;
             $e = $d->add($t1);
             $d = clone $c;
             $c = clone $b;
             $b = clone $a;
             $a = $t1->add($t2);
         }
         // Add this chunk's hash to result so far
         $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));
     }
     // Produce the final hash value (big-endian)
     // (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs.  as such, we trim the output here)
     $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . $hash[4]->toBytes() . $hash[5]->toBytes() . $hash[6]->toBytes() . $hash[7]->toBytes();
     return $temp;
 }
Ejemplo n.º 10
0
 /**
  * OpenSSL OFB Processor
  *
  * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
  * for OFB is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
  * and SymmetricKey::decrypt().
  *
  * @see self::encrypt()
  * @see self::decrypt()
  * @param string $plaintext
  * @param string $encryptIV
  * @param array $buffer
  * @return string
  * @access private
  */
 function _openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
 {
     if (strlen($buffer['xor'])) {
         $ciphertext = $plaintext ^ $buffer['xor'];
         $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
         $plaintext = substr($plaintext, strlen($ciphertext));
     } else {
         $ciphertext = '';
     }
     $block_size = $this->block_size;
     $len = strlen($plaintext);
     $key = $this->key;
     $overflow = $len % $block_size;
     if (strlen($plaintext)) {
         if ($overflow) {
             $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("", $block_size), $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
             $xor = $this->_string_pop($ciphertext, $block_size);
             if ($this->continuousBuffer) {
                 $encryptIV = $xor;
             }
             $ciphertext .= Strings::shift($xor, $overflow) ^ substr($plaintext, -$overflow);
             if ($this->continuousBuffer) {
                 $buffer['xor'] = $xor;
             }
         } else {
             $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, $this->openssl_options, $encryptIV);
             if ($this->continuousBuffer) {
                 $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
             }
         }
     }
     return $ciphertext;
 }
Ejemplo n.º 11
0
 /**
  * Logs data packets
  *
  * Makes sure that only the last 1MB worth of packets will be logged
  *
  * @param string $data
  * @access private
  */
 function _append_log($protocol_flags, $message)
 {
     switch (NET_SSH1_LOGGING) {
         // useful for benchmarks
         case self::LOG_SIMPLE:
             $this->protocol_flags_log[] = $protocol_flags;
             break;
             // the most useful log for SSH1
         // the most useful log for SSH1
         case self::LOG_COMPLEX:
             $this->protocol_flags_log[] = $protocol_flags;
             Strings::shift($message);
             $this->log_size += strlen($message);
             $this->message_log[] = $message;
             while ($this->log_size > self::LOG_MAX_SIZE) {
                 $this->log_size -= strlen(array_shift($this->message_log));
                 array_shift($this->protocol_flags_log);
             }
             break;
             // dump the output out realtime; packets may be interspersed with non packets,
             // passwords won't be filtered out and select other packets may not be correctly
             // identified
         // dump the output out realtime; packets may be interspersed with non packets,
         // passwords won't be filtered out and select other packets may not be correctly
         // identified
         case self::LOG_REALTIME:
             echo "<pre>\r\n" . $this->_format_log(array($message), array($protocol_flags)) . "\r\n</pre>\r\n";
             @flush();
             @ob_flush();
             break;
             // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
             // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
             // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
             // at the beginning of the file
         // basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
         // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
         // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
         // at the beginning of the file
         case self::LOG_REALTIME_FILE:
             if (!isset($this->realtime_log_file)) {
                 // PHP doesn't seem to like using constants in fopen()
                 $filename = self::LOG_REALTIME_FILE;
                 $fp = fopen($filename, 'w');
                 $this->realtime_log_file = $fp;
             }
             if (!is_resource($this->realtime_log_file)) {
                 break;
             }
             $entry = $this->_format_log(array($message), array($protocol_flags));
             if ($this->realtime_log_wrap) {
                 $temp = "<<< START >>>\r\n";
                 $entry .= $temp;
                 fseek($this->realtime_log_file, ftell($this->realtime_log_file) - strlen($temp));
             }
             $this->realtime_log_size += strlen($entry);
             if ($this->realtime_log_size > self::LOG_MAX_SIZE) {
                 fseek($this->realtime_log_file, 0);
                 $this->realtime_log_size = strlen($entry);
                 $this->realtime_log_wrap = true;
             }
             fputs($this->realtime_log_file, $entry);
     }
 }