setPrime($prime); $this->setGenerator($generator); if ($privateKey !== null) { $this->setPrivateKey($privateKey, $privateKeyType); } $this->setBigIntegerMath(); } /** * Generate own public key. If a private number has not already been * set, one will be generated at this stage. * * @return Zend_Crypt_DiffieHellman */ public function generateKeys() { if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { $details = array(); $details['p'] = $this->getPrime(); $details['g'] = $this->getGenerator(); if ($this->hasPrivateKey()) { $details['priv_key'] = $this->getPrivateKey(); } $opensslKeyResource = openssl_pkey_new( array('dh' => $details) ); $data = openssl_pkey_get_details($opensslKeyResource); $this->setPrivateKey($data['dh']['priv_key'], self::BINARY); $this->setPublicKey($data['dh']['pub_key'], self::BINARY); } else { // Private key is lazy generated in the absence of PHP 5.3's ext/openssl $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime()); $this->setPublicKey($publicKey); } return $this; } /** * Setter for the value of the public number * * @param string $number * @param string $type * @return Zend_Crypt_DiffieHellman */ public function setPublicKey($number, $type = self::NUMBER) { if ($type == self::BINARY) { $number = $this->_math->fromBinary($number); } if (!preg_match("/^\d+$/", $number)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); } $this->_publicKey = (string) $number; return $this; } /** * Returns own public key for communication to the second party to this * transaction. * * @param string $type * @return string */ public function getPublicKey($type = self::NUMBER) { if ($this->_publicKey === null) { require_once 'Zend/Crypt/DiffieHellman/Exception.php'; throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()'); } if ($type == self::BINARY) { return $this->_math->toBinary($this->_publicKey); } elseif ($type == self::BTWOC) { return $this->_math->btwoc($this->_math->toBinary($this->_publicKey)); } return $this->_publicKey; } /** * Compute the shared secret key based on the public key received from the * the second party to this transaction. This should agree to the secret * key the second party computes on our own public key. * Once in agreement, the key is known to only to both parties. * By default, the function expects the public key to be in binary form * which is the typical format when being transmitted. * * If you need the binary form of the shared secret key, call * getSharedSecretKey() with the optional parameter for Binary output. * * @param string $publicKey * @param string $type * @return mixed */ public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER) { if ($type == self::BINARY) { $publicKey = $this->_math->fromBinary($publicKey); } if (!preg_match("/^\d+$/", $publicKey)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); } if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) { $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey()); } else { $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime()); } return $this->getSharedSecretKey($output); } /** * Return the computed shared secret key from the DiffieHellman transaction * * @param string $type * @return string */ public function getSharedSecretKey($type = self::NUMBER) { if (!isset($this->_secretKey)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()'); } if ($type == self::BINARY) { return $this->_math->toBinary($this->_secretKey); } elseif ($type == self::BTWOC) { return $this->_math->btwoc($this->_math->toBinary($this->_secretKey)); } return $this->_secretKey; } /** * Setter for the value of the prime number * * @param string $number * @return Zend_Crypt_DiffieHellman */ public function setPrime($number) { if (!preg_match("/^\d+$/", $number) || $number < 11) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime'); } $this->_prime = (string) $number; return $this; } /** * Getter for the value of the prime number * * @return string */ public function getPrime() { if (!isset($this->_prime)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set'); } return $this->_prime; } /** * Setter for the value of the generator number * * @param string $number * @return Zend_Crypt_DiffieHellman */ public function setGenerator($number) { if (!preg_match("/^\d+$/", $number) || $number < 2) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1'); } $this->_generator = (string) $number; return $this; } /** * Getter for the value of the generator number * * @return string */ public function getGenerator() { if (!isset($this->_generator)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set'); } return $this->_generator; } /** * Setter for the value of the private number * * @param string $number * @param string $type * @return Zend_Crypt_DiffieHellman */ public function setPrivateKey($number, $type = self::NUMBER) { if ($type == self::BINARY) { $number = $this->_math->fromBinary($number); } if (!preg_match("/^\d+$/", $number)) { require_once('Zend/Crypt/DiffieHellman/Exception.php'); throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number'); } $this->_privateKey = (string) $number; return $this; } /** * Getter for the value of the private number * * @param string $type * @return string */ public function getPrivateKey($type = self::NUMBER) { if (!$this->hasPrivateKey()) { $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY); } if ($type == self::BINARY) { return $this->_math->toBinary($this->_privateKey); } elseif ($type == self::BTWOC) { return $this->_math->btwoc($this->_math->toBinary($this->_privateKey)); } return $this->_privateKey; } /** * Check whether a private key currently exists. * * @return boolean */ public function hasPrivateKey() { return isset($this->_privateKey); } /** * Setter to pass an extension parameter which is used to create * a specific BigInteger instance for a specific extension type. * Allows manual setting of the class in case of an extension * problem or bug. * * @param string $extension * @return void */ public function setBigIntegerMath($extension = null) { /** * @see Zend_Crypt_Math */ require_once 'Zend/Crypt/Math.php'; $this->_math = new Zend_Crypt_Math($extension); } /** * In the event a private number/key has not been set by the user, * or generated by ext/openssl, a best attempt will be made to * generate a random key. Having a random number generator installed * on linux/bsd is highly recommended! The alternative is not recommended * for production unless without any other option. * * @return string */ protected function _generatePrivateKey() { $rand = $this->_math->rand($this->getGenerator(), $this->getPrime()); return $rand; } }