/** * 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); }
protected function createResponse(\fpoirotte\Pssht\Wire\Decoder $decoder, \fpoirotte\Pssht\Transport $transport, array &$context, $hostAlgo) { $kexAlgo = $context['kexAlgo']; $kexAlgo = new $kexAlgo(); $message = \fpoirotte\Pssht\Messages\KEXDH\INIT::unserialize($decoder); /* // @TODO: we ought to check whether the given public key is valid. // // Unfortunately, the current API is broken as getQ() only exists // for ECDH. Also, even though the regular DH has a getE() method, // it returns raw GMP resources/objects which are unusable here. if (!$message->getQ()->isValid()) { throw new \InvalidArgumentException(); } */ return new \fpoirotte\Pssht\Messages\KEXDH\REPLY($message, $context['serverKeys'][$hostAlgo], $transport->getEncryptor(), $kexAlgo, $context['kex']['server'], $context['kex']['client'], $context['identity']['server'], $context['identity']['client']); }
public static function addHandlers(\fpoirotte\Pssht\Transport $transport) { $transport->setHandler(\fpoirotte\Pssht\Messages\KEXDH\INIT::getMessageId(), new \fpoirotte\Pssht\Handlers\KEXDH\INIT()); }