00001 <?php
00033 class Zend_Crypt_DiffieHellman
00034 {
00035
00042 public static $useOpenssl = true;
00043
00049 private $_prime = null;
00050
00057 private $_generator = null;
00058
00065 private $_privateKey = null;
00066
00072 private $_math = null;
00073
00079 private $_publicKey = null;
00080
00087 private $_secretKey = null;
00088
00092 const BINARY = 'binary';
00093 const NUMBER = 'number';
00094 const BTWOC = 'btwoc';
00095
00107 public function __construct($prime, $generator, $privateKey = null, $privateKeyType = self::NUMBER)
00108 {
00109 $this->setPrime($prime);
00110 $this->setGenerator($generator);
00111 if (!is_null($privateKey)) {
00112 $this->setPrivateKey($privateKey, $privateKeyType);
00113 }
00114 $this->setBigIntegerMath();
00115 }
00116
00123 public function generateKeys()
00124 {
00125 if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) {
00126 $details = array();
00127 $details['p'] = $this->getPrime();
00128 $details['g'] = $this->getGenerator();
00129 if ($this->hasPrivateKey()) {
00130 $details['priv_key'] = $this->getPrivateKey();
00131 }
00132 $opensslKeyResource = openssl_pkey_new( array('dh' => $details) );
00133 $data = openssl_pkey_get_details($opensslKeyResource);
00134 $this->setPrivateKey($data['dh']['priv_key'], self::BINARY);
00135 $this->setPublicKey($data['dh']['pub_key'], self::BINARY);
00136 } else {
00137
00138 $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime());
00139 $this->setPublicKey($publicKey);
00140 }
00141 return $this;
00142 }
00143
00151 public function setPublicKey($number, $type = self::NUMBER)
00152 {
00153 if ($type == self::BINARY) {
00154 $number = $this->_math->fromBinary($number);
00155 }
00156 if (!preg_match("/^\d+$/", $number)) {
00157 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00158 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
00159 }
00160 $this->_publicKey = (string) $number;
00161 return $this;
00162 }
00163
00171 public function getPublicKey($type = self::NUMBER)
00172 {
00173 if (is_null($this->_publicKey)) {
00174 require_once 'Zend/Crypt/DiffieHellman/Exception.php';
00175 throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()');
00176 }
00177 if ($type == self::BINARY) {
00178 return $this->_math->toBinary($this->_publicKey);
00179 } elseif ($type == self::BTWOC) {
00180 return $this->_math->btwoc($this->_math->toBinary($this->_publicKey));
00181 }
00182 return $this->_publicKey;
00183 }
00184
00200 public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER)
00201 {
00202 if ($type == self::BINARY) {
00203 $publicKey = $this->_math->fromBinary($publicKey);
00204 }
00205 if (!preg_match("/^\d+$/", $publicKey)) {
00206 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00207 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
00208 }
00209 if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) {
00210 $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey());
00211 } else {
00212 $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime());
00213 }
00214 return $this->getSharedSecretKey($output);
00215 }
00216
00223 public function getSharedSecretKey($type = self::NUMBER)
00224 {
00225 if (!isset($this->_secretKey)) {
00226 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00227 throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()');
00228 }
00229 if ($type == self::BINARY) {
00230 return $this->_math->toBinary($this->_secretKey);
00231 } elseif ($type == self::BTWOC) {
00232 return $this->_math->btwoc($this->_math->toBinary($this->_secretKey));
00233 }
00234 return $this->_secretKey;
00235 }
00236
00243 public function setPrime($number)
00244 {
00245 if (!preg_match("/^\d+$/", $number) || $number < 11) {
00246 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00247 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime');
00248 }
00249 $this->_prime = (string) $number;
00250 return $this;
00251 }
00252
00258 public function getPrime()
00259 {
00260 if (!isset($this->_prime)) {
00261 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00262 throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set');
00263 }
00264 return $this->_prime;
00265 }
00266
00267
00274 public function setGenerator($number)
00275 {
00276 if (!preg_match("/^\d+$/", $number) || $number < 2) {
00277 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00278 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1');
00279 }
00280 $this->_generator = (string) $number;
00281 return $this;
00282 }
00283
00289 public function getGenerator()
00290 {
00291 if (!isset($this->_generator)) {
00292 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00293 throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set');
00294 }
00295 return $this->_generator;
00296 }
00297
00305 public function setPrivateKey($number, $type = self::NUMBER)
00306 {
00307 if ($type == self::BINARY) {
00308 $number = $this->_math->fromBinary($number);
00309 }
00310 if (!preg_match("/^\d+$/", $number)) {
00311 require_once('Zend/Crypt/DiffieHellman/Exception.php');
00312 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
00313 }
00314 $this->_privateKey = (string) $number;
00315 return $this;
00316 }
00317
00324 public function getPrivateKey($type = self::NUMBER)
00325 {
00326 if (!$this->hasPrivateKey()) {
00327 $this->setPrivateKey($this->_generatePrivateKey());
00328 }
00329 if ($type == self::BINARY) {
00330 return $this->_math->toBinary($this->_privateKey);
00331 } elseif ($type == self::BTWOC) {
00332 return $this->_math->btwoc($this->_math->toBinary($this->_privateKey));
00333 }
00334 return $this->_privateKey;
00335 }
00336
00342 public function hasPrivateKey()
00343 {
00344 return isset($this->_privateKey);
00345 }
00346
00356 public function setBigIntegerMath($extension = null)
00357 {
00361 require_once 'Zend/Crypt/Math.php';
00362 $this->_math = new Zend_Crypt_Math($extension);
00363 }
00364
00374 protected function _generatePrivateKey()
00375 {
00376 $rand = $this->_math->rand($this->getGenerator(), $this->getPrime());
00377 return $rand;
00378 }
00379
00380 }