[ZF-10089] Zend_Log
[zend/radio.git] / library / Zend / Crypt / DiffieHellman.php
blob1d2fd1d15b14abdaf5eeacdebb862fa6f8531a84
1 <?php
2 /**
3 * Zend Framework
5 * LICENSE
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
15 * @category Zend
16 * @package Zend_Crypt
17 * @subpackage DiffieHellman
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
19 * @license http://framework.zend.com/license/new-bsd New BSD License
20 * @version $Id$
23 /**
24 * PHP implementation of the Diffie-Hellman public key encryption algorithm.
25 * Allows two unassociated parties to establish a joint shared secret key
26 * to be used in encrypting subsequent communications.
28 * @category Zend
29 * @package Zend_Crypt
30 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
31 * @license http://framework.zend.com/license/new-bsd New BSD License
33 class Zend_Crypt_DiffieHellman
36 /**
37 * Static flag to select whether to use PHP5.3's openssl extension
38 * if available.
40 * @var boolean
42 public static $useOpenssl = true;
44 /**
45 * Default large prime number; required by the algorithm.
47 * @var string
49 private $_prime = null;
51 /**
52 * The default generator number. This number must be greater than 0 but
53 * less than the prime number set.
55 * @var string
57 private $_generator = null;
59 /**
60 * A private number set by the local user. It's optional and will
61 * be generated if not set.
63 * @var string
65 private $_privateKey = null;
67 /**
68 * BigInteger support object courtesy of Zend_Crypt_Math
70 * @var Zend_Crypt_Math_BigInteger
72 private $_math = null;
74 /**
75 * The public key generated by this instance after calling generateKeys().
77 * @var string
79 private $_publicKey = null;
81 /**
82 * The shared secret key resulting from a completed Diffie Hellman
83 * exchange
85 * @var string
87 private $_secretKey = null;
89 /**
90 * Constants
92 const BINARY = 'binary';
93 const NUMBER = 'number';
94 const BTWOC = 'btwoc';
96 /**
97 * Constructor; if set construct the object using the parameter array to
98 * set values for Prime, Generator and Private.
99 * If a Private Key is not set, one will be generated at random.
101 * @param string $prime
102 * @param string $generator
103 * @param string $privateKey
104 * @param string $privateKeyType
105 * @return void
107 public function __construct($prime, $generator, $privateKey = null, $privateKeyType = self::NUMBER)
109 $this->setPrime($prime);
110 $this->setGenerator($generator);
111 if (!is_null($privateKey)) {
112 $this->setPrivateKey($privateKey, $privateKeyType);
114 $this->setBigIntegerMath();
118 * Generate own public key. If a private number has not already been
119 * set, one will be generated at this stage.
121 * @return Zend_Crypt_DiffieHellman
123 public function generateKeys()
125 if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) {
126 $details = array();
127 $details['p'] = $this->getPrime();
128 $details['g'] = $this->getGenerator();
129 if ($this->hasPrivateKey()) {
130 $details['priv_key'] = $this->getPrivateKey();
132 $opensslKeyResource = openssl_pkey_new( array('dh' => $details) );
133 $data = openssl_pkey_get_details($opensslKeyResource);
134 $this->setPrivateKey($data['dh']['priv_key'], self::BINARY);
135 $this->setPublicKey($data['dh']['pub_key'], self::BINARY);
136 } else {
137 // Private key is lazy generated in the absence of PHP 5.3's ext/openssl
138 $publicKey = $this->_math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime());
139 $this->setPublicKey($publicKey);
141 return $this;
145 * Setter for the value of the public number
147 * @param string $number
148 * @param string $type
149 * @return Zend_Crypt_DiffieHellman
151 public function setPublicKey($number, $type = self::NUMBER)
153 if ($type == self::BINARY) {
154 $number = $this->_math->fromBinary($number);
156 if (!preg_match("/^\d+$/", $number)) {
157 require_once('Zend/Crypt/DiffieHellman/Exception.php');
158 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
160 $this->_publicKey = (string) $number;
161 return $this;
165 * Returns own public key for communication to the second party to this
166 * transaction.
168 * @param string $type
169 * @return string
171 public function getPublicKey($type = self::NUMBER)
173 if (is_null($this->_publicKey)) {
174 require_once 'Zend/Crypt/DiffieHellman/Exception.php';
175 throw new Zend_Crypt_DiffieHellman_Exception('A public key has not yet been generated using a prior call to generateKeys()');
177 if ($type == self::BINARY) {
178 return $this->_math->toBinary($this->_publicKey);
179 } elseif ($type == self::BTWOC) {
180 return $this->_math->btwoc($this->_math->toBinary($this->_publicKey));
182 return $this->_publicKey;
186 * Compute the shared secret key based on the public key received from the
187 * the second party to this transaction. This should agree to the secret
188 * key the second party computes on our own public key.
189 * Once in agreement, the key is known to only to both parties.
190 * By default, the function expects the public key to be in binary form
191 * which is the typical format when being transmitted.
193 * If you need the binary form of the shared secret key, call
194 * getSharedSecretKey() with the optional parameter for Binary output.
196 * @param string $publicKey
197 * @param string $type
198 * @return mixed
200 public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER)
202 if ($type == self::BINARY) {
203 $publicKey = $this->_math->fromBinary($publicKey);
205 if (!preg_match("/^\d+$/", $publicKey)) {
206 require_once('Zend/Crypt/DiffieHellman/Exception.php');
207 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
209 if (function_exists('openssl_dh_compute_key') && self::$useOpenssl !== false) {
210 $this->_secretKey = openssl_dh_compute_key($publicKey, $this->getPublicKey());
211 } else {
212 $this->_secretKey = $this->_math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime());
214 return $this->getSharedSecretKey($output);
218 * Return the computed shared secret key from the DiffieHellman transaction
220 * @param string $type
221 * @return string
223 public function getSharedSecretKey($type = self::NUMBER)
225 if (!isset($this->_secretKey)) {
226 require_once('Zend/Crypt/DiffieHellman/Exception.php');
227 throw new Zend_Crypt_DiffieHellman_Exception('A secret key has not yet been computed; call computeSecretKey()');
229 if ($type == self::BINARY) {
230 return $this->_math->toBinary($this->_secretKey);
231 } elseif ($type == self::BTWOC) {
232 return $this->_math->btwoc($this->_math->toBinary($this->_secretKey));
234 return $this->_secretKey;
238 * Setter for the value of the prime number
240 * @param string $number
241 * @return Zend_Crypt_DiffieHellman
243 public function setPrime($number)
245 if (!preg_match("/^\d+$/", $number) || $number < 11) {
246 require_once('Zend/Crypt/DiffieHellman/Exception.php');
247 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number or too small: should be a large natural number prime');
249 $this->_prime = (string) $number;
250 return $this;
254 * Getter for the value of the prime number
256 * @return string
258 public function getPrime()
260 if (!isset($this->_prime)) {
261 require_once('Zend/Crypt/DiffieHellman/Exception.php');
262 throw new Zend_Crypt_DiffieHellman_Exception('No prime number has been set');
264 return $this->_prime;
269 * Setter for the value of the generator number
271 * @param string $number
272 * @return Zend_Crypt_DiffieHellman
274 public function setGenerator($number)
276 if (!preg_match("/^\d+$/", $number) || $number < 2) {
277 require_once('Zend/Crypt/DiffieHellman/Exception.php');
278 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number greater than 1');
280 $this->_generator = (string) $number;
281 return $this;
285 * Getter for the value of the generator number
287 * @return string
289 public function getGenerator()
291 if (!isset($this->_generator)) {
292 require_once('Zend/Crypt/DiffieHellman/Exception.php');
293 throw new Zend_Crypt_DiffieHellman_Exception('No generator number has been set');
295 return $this->_generator;
299 * Setter for the value of the private number
301 * @param string $number
302 * @param string $type
303 * @return Zend_Crypt_DiffieHellman
305 public function setPrivateKey($number, $type = self::NUMBER)
307 if ($type == self::BINARY) {
308 $number = $this->_math->fromBinary($number);
310 if (!preg_match("/^\d+$/", $number)) {
311 require_once('Zend/Crypt/DiffieHellman/Exception.php');
312 throw new Zend_Crypt_DiffieHellman_Exception('invalid parameter; not a positive natural number');
314 $this->_privateKey = (string) $number;
315 return $this;
319 * Getter for the value of the private number
321 * @param string $type
322 * @return string
324 public function getPrivateKey($type = self::NUMBER)
326 if (!$this->hasPrivateKey()) {
327 $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY);
329 if ($type == self::BINARY) {
330 return $this->_math->toBinary($this->_privateKey);
331 } elseif ($type == self::BTWOC) {
332 return $this->_math->btwoc($this->_math->toBinary($this->_privateKey));
334 return $this->_privateKey;
338 * Check whether a private key currently exists.
340 * @return boolean
342 public function hasPrivateKey()
344 return isset($this->_privateKey);
348 * Setter to pass an extension parameter which is used to create
349 * a specific BigInteger instance for a specific extension type.
350 * Allows manual setting of the class in case of an extension
351 * problem or bug.
353 * @param string $extension
354 * @return void
356 public function setBigIntegerMath($extension = null)
359 * @see Zend_Crypt_Math
361 require_once 'Zend/Crypt/Math.php';
362 $this->_math = new Zend_Crypt_Math($extension);
366 * In the event a private number/key has not been set by the user,
367 * or generated by ext/openssl, a best attempt will be made to
368 * generate a random key. Having a random number generator installed
369 * on linux/bsd is highly recommended! The alternative is not recommended
370 * for production unless without any other option.
372 * @return string
374 protected function _generatePrivateKey()
376 $rand = $this->_math->rand($this->getGenerator(), $this->getPrime());
377 return $rand;