public static function add(\fpoirotte\Pssht\ECC\Curve $curve, \fpoirotte\Pssht\ECC\Point $P, \fpoirotte\Pssht\ECC\Point $Q) { $mod = $curve->getModulus(); $xP = $P->coordinates['x']; $yP = $P->coordinates['y']; $xQ = $Q->coordinates['x']; $yQ = $Q->coordinates['y']; if (!gmp_cmp($xP, $xQ) && !gmp_cmp($yP, $yQ)) { $alphanum = gmp_add(gmp_mul('3', gmp_pow($xP, '2')), $curve->getA()); $alphaden = gmp_mul('2', $yP); } else { $alphanum = gmp_sub($yQ, $yP); $alphaden = gmp_sub($xQ, $xP); } $bezout = gmp_gcdext($alphaden, $mod); $alpha = gmp_mod(gmp_mul($alphanum, $bezout['s']), $mod); $xR = gmp_sub(gmp_sub(gmp_pow($alpha, '2'), $xP), $xQ); $yR = gmp_sub(gmp_mul($alpha, gmp_sub($xP, $xR)), $yP); return new static(gmp_mod(gmp_add($xR, $mod), $mod), gmp_mod(gmp_add($yR, $mod), $mod)); }
/** * 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); }