public function authenticate(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message, \fpoirotte\Pssht\Transport $transport, array &$context) { if (!$message instanceof \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\PublicKey) { throw new \InvalidArgumentException(); } if ($message->getSignature() === null) { return self::AUTH_REJECT; } $logging = \Plop\Plop::getInstance(); $reverse = gethostbyaddr($transport->getAddress()); $algos = \fpoirotte\Pssht\Algorithms::factory(); $cls = $algos->getClass('PublicKey', $message->getAlgorithm()); if ($cls === null || !$this->store->exists($message->getUserName(), $message->getKey())) { $logging->info('Rejected public key connection from remote host "%(reverse)s" ' . 'to "%(luser)s" (unsupported key)', array('luser' => escape($message->getUserName()), 'reverse' => $reverse)); return self::AUTH_REJECT; } $key = $cls::loadPublic(base64_encode($message->getKey())); $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $encoder->encodeString($context['DH']->getExchangeHash()); $encoder->encodeBytes(chr(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base::getMessageId())); $encoder->encodeString($message->getUserName()); $encoder->encodeString($message->getServiceName()); $encoder->encodeString(static::getName()); $encoder->encodeBoolean(true); $encoder->encodeString($message->getAlgorithm()); $encoder->encodeString($message->getKey()); if ($key->check($encoder->getBuffer()->get(0), $message->getSignature())) { $logging->info('Accepted public key connection from remote host "%(reverse)s" ' . 'to "%(luser)s" (using "%(algorithm)s" algorithm)', array('luser' => escape($message->getUserName()), 'reverse' => $reverse, 'algorithm' => escape($message->getAlgorithm()))); return self::AUTH_ACCEPT; } $logging->info('Rejected public key connection from remote host "%(reverse)s" ' . 'to "%(luser)s" (invalid signature)', array('luser' => escape($message->getUserName()), 'reverse' => $reverse)); return self::AUTH_REJECT; }
public final function compute($seqno, $data) { $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $nonce = $encoder->encodeUint64($seqno)->getBuffer()->get(0); $res = $this->umac->umac($this->key, $data, $nonce); return $res; }
public function handle($msgType, \fpoirotte\Pssht\Wire\Decoder $decoder, \fpoirotte\Pssht\Transport $transport, array &$context) { unset($context['rekeying']); $response = new \fpoirotte\Pssht\Messages\NEWKEYS(); $transport->writeMessage($response); $logging = \Plop\Plop::getInstance(); // Reset the various keys. $kexAlgo = $context['kexAlgo']; $kexAlgo = new $kexAlgo(); $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $encoder->encodeMpint($context['DH']->getSharedSecret()); $sharedSecret = $encoder->getBuffer()->get(0); $exchangeHash = $context['DH']->getExchangeHash(); $sessionId = $context['sessionIdentifier']; $limiters = array('A' => array($context['C2S']['Encryption'], 'getIVSize'), 'B' => array($context['S2C']['Encryption'], 'getIVSize'), 'C' => array($context['C2S']['Encryption'], 'getKeySize'), 'D' => array($context['S2C']['Encryption'], 'getKeySize'), 'E' => array($context['C2S']['MAC'], 'getKeySize'), 'F' => array($context['C2S']['MAC'], 'getKeySize')); $shared = gmp_strval($context['DH']->getSharedSecret(), 16); $shared = str_pad($shared, strlen($shared) + 1 >> 1 << 1, '0', STR_PAD_LEFT); $logging->debug('Key exchange: %s', array($context['kexAlgo'])); $logging->debug('Shared secret: %s', array(wordwrap($shared, 16, ' ', true))); $logging->debug('Hash: %s', array(wordwrap(bin2hex($exchangeHash), 16, ' ', true))); foreach (array('A', 'B', 'C', 'D', 'E', 'F') as $keyIndex) { $key = $kexAlgo->hash($sharedSecret . $exchangeHash . $keyIndex . $sessionId); $limit = call_user_func($limiters[$keyIndex]); while (strlen($key) < $limit) { $key .= $kexAlgo->hash($sharedSecret . $exchangeHash . $key); } $key = (string) substr($key, 0, $limit); $context['keys'][$keyIndex] = $key; $logging->debug('Key %(keyName)s: %(keyValue)s', array('keyName' => $keyIndex, 'keyValue' => wordwrap(bin2hex($key), 16, ' ', true))); } // Encryption $cls = $context['C2S']['Encryption']; $transport->setDecryptor(new $cls($context['keys']['A'], $context['keys']['C'])); $logging->debug('C2S Encryption: %s', array($cls)); $cls = $context['S2C']['Encryption']; $transport->setEncryptor(new $cls($context['keys']['B'], $context['keys']['D'])); $logging->debug('S2C Encryption: %s', array($cls)); // MAC $cls = $context['C2S']['MAC']; $transport->setInputMAC(new $cls($context['keys']['E'])); $logging->debug('C2S MAC: %s', array($cls)); $cls = $context['S2C']['MAC']; $transport->setOutputMAC(new $cls($context['keys']['F'])); $logging->debug('S2C MAC: %s', array($cls)); // Compression $cls = $context['C2S']['Compression']; $transport->setUncompressor(new $cls(CompressionInterface::MODE_UNCOMPRESS)); $logging->debug('C2S Compression: %s', array($cls)); $cls = $context['S2C']['Compression']; $transport->setCompressor(new $cls(CompressionInterface::MODE_COMPRESS)); $logging->debug('S2C Compression: %s', array($cls)); return true; }
public function handle($msgType, \fpoirotte\Pssht\Wire\Decoder $decoder, \fpoirotte\Pssht\Transport $transport, array &$context) { $localChannel = $decoder->decodeUint32(); $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $encoder->encodeUint32($localChannel); $decoder->getBuffer()->unget($encoder->getBuffer()->get(0)); if (isset($this->handlers[$localChannel][$msgType])) { $handler = $this->handlers[$localChannel][$msgType]; $logging = \Plop\Plop::getInstance(); $logging->debug('Calling %(handler)s for channel #%(channel)d ' . 'with message type #%(msgType)d', array('handler' => get_class($handler) . '::handle', 'channel' => $localChannel, 'msgType' => $msgType)); return $handler->handle($msgType, $decoder, $transport, $context); } return true; }
public function serialize(\fpoirotte\Pssht\Wire\Encoder $encoder) { parent::serialize($encoder); $encoder->encodeBoolean($this->signature !== null); $encoder->encodeString($this->algorithm); $encoder->encodeString($this->key); if ($this->signature !== null) { $encoder2 = new \fpoirotte\Pssht\Wire\Encoder(); $encoder2->encodeString($this->algorithm); $encoder2->encodeString($this->signature); $encoder->encodeString($encoder2->getBuffer()->get(0)); } return $this; }
public function serialize(\fpoirotte\Pssht\Wire\Encoder $encoder) { parent::serialize($encoder); $encoder->encodeString($this->algorithm); $encoder->encodeString($this->key); $encoder->encodeString($this->hostname); $encoder->encodeString($this->remoteUser); // Special handling of the signature. $encoder2 = new \fpoirotte\Pssht\Wire\Encoder(); $encoder2->encodeString($this->algorithm); $encoder2->encodeString($this->signature); $encoder->encodeString($encoder2->getBuffer()->get(0)); return $this; }
public function handle($msgType, \fpoirotte\Pssht\Wire\Decoder $decoder, \fpoirotte\Pssht\Transport $transport, array &$context) { $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $channel = $decoder->decodeUint32(); $type = $decoder->decodeString(); $wantsReply = $decoder->decodeBoolean(); $encoder->encodeUint32($channel); $encoder->encodeString($type); $encoder->encodeBoolean($wantsReply); $decoder->getBuffer()->unget($encoder->getBuffer()->get(0)); $remoteChannel = $this->connection->getChannel($channel); switch ($type) { case 'exec': case 'shell': case 'pty-req': // Normalize the name. // Eg. "pty-req" becomes "PtyReq". $cls = str_replace(' ', '', ucwords(str_replace('-', ' ', $type))); $cls = '\\fpoirotte\\Pssht\\Messages\\CHANNEL\\REQUEST\\' . $cls; $message = $cls::unserialize($decoder); break; default: if ($wantsReply) { $response = new \fpoirotte\Pssht\Messages\CHANNEL\FAILURE($remoteChannel); $transport->writeMessage($response); } return true; } if (!$wantsReply) { return true; } if (in_array($type, array('shell', 'exec'), true)) { $response = new \fpoirotte\Pssht\Messages\CHANNEL\SUCCESS($remoteChannel); } else { $response = new \fpoirotte\Pssht\Messages\CHANNEL\FAILURE($remoteChannel); } $transport->writeMessage($response); if (in_array($type, array('shell', 'exec'), true)) { $callable = $transport->getApplicationFactory(); if ($callable !== null) { call_user_func($callable, $transport, $this->connection, $message); } } return true; }
/** * Construct a new SSH_MSG_KEXDH_REPLY message. * * \param fpoirotte::Pssht::Messages::KEXDH::INIT $kexDHInit * Client's contribution to the Diffie-Hellman Key Exchange. * * \param fpoirotte::Pssht::PublicKeyInterface $key * Server's public key. * * \param fpoirotte::Pssht::EncryptionInterface $encryptionAlgo * Encryption algorithm in use. * * \param fpoirotte::Pssht::KEXInterface $kexAlgo * Key exchange algorithm to use. * * \param fpoirotte::Pssht::Messages::KEXINIT $serverKEX * Algorithms supported by the server. * * \param fpoirotte::Pssht::Messages::KEXINIT $clientKEX * Algorithms supported by the client. * * \param string $serverIdent * Server's identification string * * \param string $clientIdent * Client's identification string */ public function __construct(\fpoirotte\Pssht\Messages\KEXDH\INIT $kexDHInit, \fpoirotte\Pssht\PublicKeyInterface $key, \fpoirotte\Pssht\EncryptionInterface $encryptionAlgo, \fpoirotte\Pssht\KEXInterface $kexAlgo, \fpoirotte\Pssht\Messages\KEXINIT $serverKEX, \fpoirotte\Pssht\Messages\KEXINIT $clientKEX, $serverIdent, $clientIdent) { if (!is_string($serverIdent)) { throw new \InvalidArgumentException(); } if (!is_string($clientIdent)) { throw new \InvalidArgumentException(); } $keyLength = min(20, max($encryptionAlgo->getKeySize(), 16)); $randBytes = openssl_random_pseudo_bytes(2 * $keyLength); $y = gmp_init(bin2hex($randBytes), 16); $prime = gmp_init($kexAlgo::getPrime(), 16); $this->f = gmp_powm($kexAlgo::getGenerator(), $y, $prime); $this->K = gmp_powm($kexDHInit->getE(), $y, $prime); $this->K_S = $key; $this->kexDHInit = $kexDHInit; $this->kexAlgo = $kexAlgo; $this->serverKEX = $serverKEX; $this->clientKEX = $clientKEX; $this->serverIdent = $serverIdent; $this->clientIdent = $clientIdent; $msgId = chr(\fpoirotte\Pssht\Messages\KEXINIT::getMessageId()); // $sub is used to create the structure for the hashing function. $sub = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer()); $this->K_S->serialize($sub); $K_S = $sub->getBuffer()->get(0); $sub->encodeString($this->clientIdent); $sub->encodeString($this->serverIdent); // $sub2 is used to compute the value // of various fields inside the structure. $sub2 = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer()); $sub2->encodeBytes($msgId); // Add message identifier. $this->clientKEX->serialize($sub2); $sub->encodeString($sub2->getBuffer()->get(0)); $sub2->encodeBytes($msgId); // Add message identifier. $this->serverKEX->serialize($sub2); $sub->encodeString($sub2->getBuffer()->get(0)); $sub->encodeString($K_S); $sub->encodeMpint($this->kexDHInit->getE()); $sub->encodeMpint($this->f); $sub->encodeMpint($this->K); $logging = \Plop\Plop::getInstance(); $origData = $sub->getBuffer()->get(0); $data = wordwrap(bin2hex($origData), 4, ' ', true); $data = wordwrap($data, 32 + 7, PHP_EOL, true); $logging->debug("Signature payload:\r\n%s", array($data)); $this->H = $this->kexAlgo->hash($origData); }
/** * Write an SSH message into the output buffer. * * \param fpoirotte::Pssht::MessageInterface $message * Message to write into the output buffer. * * \retval Transport * Returns this transport layer. */ public function writeMessage(\fpoirotte\Pssht\MessageInterface $message) { $logging = \Plop\Plop::getInstance(); // Serialize the message. $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $encoder->encodeBytes(chr($message::getMessageId())); $message->serialize($encoder); $payload = $encoder->getBuffer()->get(0); $logging->debug('Sending payload: %s', array(\escape($payload))); // Compress the payload if necessary. $payload = $this->compressor->update($payload); $size = strlen($payload); $blockSize = max(8, $this->encryptor->getBlockSize()); // Compute padding requirements. // See http://api.libssh.org/rfc/PROTOCOL // for more information on EtM (Encrypt-then-MAC) // and RFCs 5116 & 5647 for AEAD & AES-GCM. if ($this->outMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) { $padSize = $blockSize - (1 + $size) % $blockSize; } elseif ($this->encryptor instanceof \fpoirotte\Pssht\AEADInterface) { $padSize = $blockSize - (1 + $size) % $blockSize; } else { $padSize = $blockSize - (1 + 4 + $size) % $blockSize; } if ($padSize < 4) { $padSize = ($padSize + $blockSize) % 256; } $padding = openssl_random_pseudo_bytes($padSize); // Create the packet. Every content passed to $encoder // will be encrypted, except possibly for the packet // length (see below). $encoder->encodeUint32(1 + $size + $padSize); if ($this->outMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) { // Send the packet length in plaintext. $encSize = $encoder->getBuffer()->get(0); $this->encoder->encodeBytes($encSize); } $encoder->encodeBytes(chr($padSize)); $encoder->encodeBytes($payload); $encoder->encodeBytes($padding); $packet = $encoder->getBuffer()->get(0); $encrypted = $this->encryptor->encrypt($this->outSeqNo, $packet); // Compute the MAC. if ($this->outMAC instanceof \fpoirotte\Pssht\MAC\OpensshCom\EtM\EtMInterface) { $mac = $this->outMAC->compute($this->outSeqNo, $encSize . $encrypted); } else { $mac = $this->outMAC->compute($this->outSeqNo, $packet); } // Send the packet on the wire. $this->encoder->encodeBytes($encrypted); $this->encoder->encodeBytes($mac); $this->outSeqNo = ++$this->outSeqNo & 0xffffffff; $logging->debug('Sending %(type)s packet ' . '(size: %(size)d, payload: %(payload)d, ' . 'block: %(block)d, padding: %(padding)d)', array('type' => get_class($message), 'size' => strlen($encrypted), 'payload' => $size, 'block' => $blockSize, 'padding' => $padSize)); return $this; }
public function handle($msgType, \fpoirotte\Pssht\Wire\Decoder $decoder, \fpoirotte\Pssht\Transport $transport, array &$context) { if ($this->connection !== null) { // Silently ignore subsequent authentication requests // after a successful authentication took place. return true; } $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $user = $decoder->decodeString(); $service = $decoder->decodeString(); $method = $decoder->decodeString(); $encoder->encodeString($user); $encoder->encodeString($service); $encoder->encodeString($method); $decoder->getBuffer()->unget($encoder->getBuffer()->get(0)); if (!isset($context['authMethods'])) { $context['authMethods'] = $this->methods; } if (!isset($context['banner'])) { $context['banner'] = (string) $transport->getBanner(); if ($context['banner'] !== '') { $response = new \fpoirotte\Pssht\Messages\USERAUTH\BANNER($context['banner']); $transport->writeMessage($response); } } if (!isset($context['authMethods'][$method])) { return $this->failure($transport, $context); } $messagesCls = array('none' => '\\fpoirotte\\Pssht\\Messages\\USERAUTH\\REQUEST\\None', 'hostbased' => '\\fpoirotte\\Pssht\\Messages\\USERAUTH\\REQUEST\\HostBased', 'password' => '\\fpoirotte\\Pssht\\Messages\\USERAUTH\\REQUEST\\Password', 'publickey' => '\\fpoirotte\\Pssht\\Messages\\USERAUTH\\REQUEST\\PublicKey'); $methodObj = $context['authMethods'][$method]; $message = $messagesCls[$method]::unserialize($decoder); switch ($methodObj->check($message, $transport, $context)) { case AuthenticationInterface::CHECK_IGNORE: return true; case AuthenticationInterface::CHECK_REJECT: return $this->failure($transport, $context); case AuthenticationInterface::CHECK_OK: break; default: throw new \RuntimeException(); } switch ($methodObj->authenticate($message, $transport, $context)) { case AuthenticationInterface::AUTH_REMOVE: unset($context['authMethods'][$method]); // Do not break. // Do not break. case AuthenticationInterface::AUTH_REJECT: return $this->failure($transport, $context); case AuthenticationInterface::AUTH_ACCEPT: break; default: throw new \RuntimeException(); } unset($context['authMethods'][$method]); $response = new \fpoirotte\Pssht\Messages\USERAUTH\SUCCESS(); $this->connection = new \fpoirotte\Pssht\Connection($transport); $transport->writeMessage($response); $compressor = $transport->getCompressor(); if ($compressor instanceof \fpoirotte\Pssht\DelayedCompressionInterface) { $compressor->setAuthenticated(); } $uncompressor = $transport->getUncompressor(); if ($uncompressor instanceof \fpoirotte\Pssht\DelayedCompressionInterface) { $uncompressor->setAuthenticated(); } return true; }
public function authenticate(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base $message, \fpoirotte\Pssht\Transport $transport, array &$context) { if (!$message instanceof \fpoirotte\Pssht\Messages\USERAUTH\REQUEST\HostBased) { throw new \InvalidArgumentException(); } $logging = \Plop\Plop::getInstance(); $reverse = gethostbyaddr($transport->getAddress()); $untrustedHost = rtrim($message->getHostname(), '.'); $algos = \fpoirotte\Pssht\Algorithms::factory(); $cls = $algos->getClass('PublicKey', $message->getAlgorithm()); if ($cls === null || !$this->store->exists($message->getUserName(), $message->getKey())) { $logging->info('Rejected host based connection from %(ruser)s@%(rhost)s ' . '(%(ruser)s@%(reverse)s) to "%(luser)s" ' . '(unsupported key)', array('ruser' => escape($message->getRemoteUser()), 'luser' => escape($message->getUserName()), 'rhost' => escape($untrustedHost), 'reverse' => $reverse)); return self::AUTH_REMOVE; } $key = $cls::loadPublic(base64_encode($message->getKey())); $encoder = new \fpoirotte\Pssht\Wire\Encoder(); $encoder->encodeString($context['DH']->getExchangeHash()); $encoder->encodeBytes(chr(\fpoirotte\Pssht\Messages\USERAUTH\REQUEST\Base::getMessageId())); $encoder->encodeString($message->getUserName()); $encoder->encodeString($message->getServiceName()); $encoder->encodeString(static::getName()); $encoder->encodeString($message->getAlgorithm()); $encoder->encodeString($message->getKey()); $encoder->encodeString($message->getHostname()); $encoder->encodeString($message->getRemoteUser()); if (!$key->check($encoder->getBuffer()->get(0), $message->getSignature())) { $logging->warn('Rejected host based connection from %(ruser)s@%(rhost)s ' . '(%(ruser)s@%(reverse)s) to "%(luser)s" (invalid signature)', array('ruser' => escape($message->getRemoteUser()), 'luser' => escape($message->getUserName()), 'rhost' => escape($untrustedHost), 'reverse' => $reverse)); return self::AUTH_REJECT; } if ($reverse !== $untrustedHost) { $logging->warning('Ignored reverse lookup mismatch for %(address)s (' . '"%(reverse)s" vs. "%(untrusted)s")', array('address' => $transport->getAddress(), 'reverse' => $reverse, 'untrusted' => escape($untrustedHost))); } if ($message->getUserName() !== $message->getRemoteUser()) { $logging->warning('Rejected host based connection from %(ruser)s@%(rhost)s ' . '(%(ruser)s@%(reverse)s): remote user does not match ' . 'local user (%(luser)s)', array('ruser' => escape($message->getRemoteUser()), 'luser' => escape($message->getUserName()), 'rhost' => escape($untrustedHost), 'reverse' => $reverse)); return self::AUTH_REMOVE; } $logging->info('Accepted host based connection ' . 'from "%(ruser)s@%(rhost)s" (%(ruser)s@%(reverse)s) ' . 'to "%(luser)s" (using "%(algorithm)s" algorithm)', array('ruser' => escape($message->getRemoteUser()), 'luser' => escape($message->getUserName()), 'rhost' => escape($untrustedHost), 'reverse' => $reverse, 'algorithm' => escape($message->getAlgorithm()))); return self::AUTH_ACCEPT; }
/** * Construct a new SSH_MSG_KEXDH_REPLY message. * * \param fpoirotte::Pssht::ECC::Curve $curve * Elliptic curve in use. * * \param fpoirotte::Pssht::Messages::KEX::ECDH::INIT::RFC5656 $kexDHInit * Client's contribution to the Diffie-Hellman Key Exchange. * * \param fpoirotte::Pssht::PublicKeyInterface $key * Server's public key. * * \param fpoirotte::Pssht::EncryptionInterface $encryptionAlgo * Encryption algorithm in use. * * \param fpoirotte::Pssht::KEXInterface $kexAlgo * Key exchange algorithm to use. * * \param fpoirotte::Pssht::Messages::KEXINIT $serverKEX * Algorithms supported by the server. * * \param fpoirotte::Pssht::Messages::KEXINIT $clientKEX * Algorithms supported by the client. * * \param string $serverIdent * Server's identification string * * \param string $clientIdent * Client's identification string */ public function __construct(\fpoirotte\Pssht\ECC\Curve $curve, \fpoirotte\Pssht\Messages\KEX\ECDH\INIT\RFC5656 $kexDHInit, \fpoirotte\Pssht\PublicKeyInterface $key, \fpoirotte\Pssht\EncryptionInterface $encryptionAlgo, \fpoirotte\Pssht\KEXInterface $kexAlgo, \fpoirotte\Pssht\Messages\KEXINIT $serverKEX, \fpoirotte\Pssht\Messages\KEXINIT $clientKEX, $serverIdent, $clientIdent) { if (!is_string($serverIdent)) { throw new \InvalidArgumentException(); } if (!is_string($clientIdent)) { throw new \InvalidArgumentException(); } $len = strlen(gmp_strval($curve->getOrder(), 2)); $len = ceil($len / 8); $randBytes = openssl_random_pseudo_bytes($len); $d_S = gmp_mod(gmp_init(bin2hex($randBytes), 16), $curve->getModulus()); $this->Q_S = $curve->getGenerator()->multiply($curve, $d_S); $Q_C = $kexDHInit->getQ(); /// @FIXME this is not optimal... $algorithms = \fpoirotte\Pssht\Algorithms::factory(); $cls = $algorithms->getClass('PublicKey', 'ecdsa-sha2-' . $curve->getName()); $clientPK = new $cls($Q_C); if (!$clientPK->isValid()) { throw new \InvalidArgumentException(); } // EC Co-factor DH (sec1-v2, section 3.3.2). $P = $Q_C->multiply($curve, gmp_mul($curve->getCofactor(), $d_S)); if ($P->isIdentity($curve)) { throw new \InvalidArgumentException(); } $this->K = $P->x; $this->curve = $curve; $this->K_S = $key; $this->kexDHInit = $kexDHInit; $this->kexAlgo = $kexAlgo; $this->serverKEX = $serverKEX; $this->clientKEX = $clientKEX; $this->serverIdent = $serverIdent; $this->clientIdent = $clientIdent; $msgId = chr(\fpoirotte\Pssht\Messages\KEXINIT::getMessageId()); // $sub is used to create the structure for the hashing function. $sub = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer()); $this->K_S->serialize($sub); $K_S = $sub->getBuffer()->get(0); $sub->encodeString($this->clientIdent); $sub->encodeString($this->serverIdent); // $sub2 is used to compute the value // of various fields inside the structure. $sub2 = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer()); $sub2->encodeBytes($msgId); // Add message identifier. $this->clientKEX->serialize($sub2); $sub->encodeString($sub2->getBuffer()->get(0)); $sub2->encodeBytes($msgId); // Add message identifier. $this->serverKEX->serialize($sub2); $sub->encodeString($sub2->getBuffer()->get(0)); $sub->encodeString($K_S); $sub->encodeString($Q_C->serialize($curve)); $sub->encodeString($this->Q_S->serialize($curve)); $sub->encodeMpint($this->K); $logging = \Plop\Plop::getInstance(); $origData = $sub->getBuffer()->get(0); $data = wordwrap(bin2hex($origData), 4, ' ', true); $data = wordwrap($data, 32 + 7, PHP_EOL, true); $logging->debug("Signature payload:\r\n%s", array($data)); $this->H = $this->kexAlgo->hash($origData); }