Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Crypt / PublicKey / DiffieHellman.php
blobf88308ab66cea2488723849caf9dfecd6d921886
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Crypt\PublicKey;
12 use Zend\Crypt\Exception;
13 use Zend\Math;
15 /**
16 * PHP implementation of the Diffie-Hellman public key encryption algorithm.
17 * Allows two unassociated parties to establish a joint shared secret key
18 * to be used in encrypting subsequent communications.
20 class DiffieHellman
22 const DEFAULT_KEY_SIZE = 2048;
24 /**
25 * Key formats
27 const FORMAT_BINARY = 'binary';
28 const FORMAT_NUMBER = 'number';
29 const FORMAT_BTWOC = 'btwoc';
31 /**
32 * Static flag to select whether to use PHP5.3's openssl extension
33 * if available.
35 * @var bool
37 public static $useOpenssl = true;
39 /**
40 * Default large prime number; required by the algorithm.
42 * @var string
44 private $prime = null;
46 /**
47 * The default generator number. This number must be greater than 0 but
48 * less than the prime number set.
50 * @var string
52 private $generator = null;
54 /**
55 * A private number set by the local user. It's optional and will
56 * be generated if not set.
58 * @var string
60 private $privateKey = null;
62 /**
63 * BigInteger support object courtesy of Zend\Math
65 * @var \Zend\Math\BigInteger\Adapter\AdapterInterface
67 private $math = null;
69 /**
70 * The public key generated by this instance after calling generateKeys().
72 * @var string
74 private $publicKey = null;
76 /**
77 * The shared secret key resulting from a completed Diffie Hellman
78 * exchange
80 * @var string
82 private $secretKey = null;
84 /**
85 * @var resource
87 protected $opensslKeyResource = null;
89 /**
90 * Constructor; if set construct the object using the parameter array to
91 * set values for Prime, Generator and Private.
92 * If a Private Key is not set, one will be generated at random.
94 * @param string $prime
95 * @param string $generator
96 * @param string $privateKey
97 * @param string $privateKeyFormat
99 public function __construct($prime, $generator, $privateKey = null, $privateKeyFormat = self::FORMAT_NUMBER)
101 $this->setPrime($prime);
102 $this->setGenerator($generator);
103 if ($privateKey !== null) {
104 $this->setPrivateKey($privateKey, $privateKeyFormat);
107 // set up BigInteger adapter
108 $this->math = Math\BigInteger\BigInteger::factory();
112 * Set whether to use openssl extension
114 * @static
115 * @param bool $flag
117 public static function useOpensslExtension($flag = true)
119 static::$useOpenssl = (bool) $flag;
123 * Generate own public key. If a private number has not already been set,
124 * one will be generated at this stage.
126 * @return DiffieHellman
127 * @throws \Zend\Crypt\Exception\RuntimeException
129 public function generateKeys()
131 if (function_exists('openssl_dh_compute_key') && static::$useOpenssl !== false) {
132 $details = array(
133 'p' => $this->convert($this->getPrime(), self::FORMAT_NUMBER, self::FORMAT_BINARY),
134 'g' => $this->convert($this->getGenerator(), self::FORMAT_NUMBER, self::FORMAT_BINARY)
136 if ($this->hasPrivateKey()) {
137 $details['priv_key'] = $this->convert(
138 $this->privateKey, self::FORMAT_NUMBER, self::FORMAT_BINARY
140 $opensslKeyResource = openssl_pkey_new(array('dh' => $details));
141 } else {
142 $opensslKeyResource = openssl_pkey_new(array(
143 'dh' => $details,
144 'private_key_bits' => self::DEFAULT_KEY_SIZE,
145 'private_key_type' => OPENSSL_KEYTYPE_DH
149 if (false === $opensslKeyResource) {
150 throw new Exception\RuntimeException(
151 'Can not generate new key; openssl ' . openssl_error_string()
155 $data = openssl_pkey_get_details($opensslKeyResource);
157 $this->setPrivateKey($data['dh']['priv_key'], self::FORMAT_BINARY);
158 $this->setPublicKey($data['dh']['pub_key'], self::FORMAT_BINARY);
160 $this->opensslKeyResource = $opensslKeyResource;
161 } else {
162 // Private key is lazy generated in the absence of ext/openssl
163 $publicKey = $this->math->powmod($this->getGenerator(), $this->getPrivateKey(), $this->getPrime());
164 $this->setPublicKey($publicKey);
167 return $this;
171 * Setter for the value of the public number
173 * @param string $number
174 * @param string $format
175 * @return DiffieHellman
176 * @throws \Zend\Crypt\Exception\InvalidArgumentException
178 public function setPublicKey($number, $format = self::FORMAT_NUMBER)
180 $number = $this->convert($number, $format, self::FORMAT_NUMBER);
181 if (!preg_match('/^\d+$/', $number)) {
182 throw new Exception\InvalidArgumentException('Invalid parameter; not a positive natural number');
184 $this->publicKey = (string) $number;
186 return $this;
190 * Returns own public key for communication to the second party to this transaction
192 * @param string $format
193 * @return string
194 * @throws \Zend\Crypt\Exception\InvalidArgumentException
196 public function getPublicKey($format = self::FORMAT_NUMBER)
198 if ($this->publicKey === null) {
199 throw new Exception\InvalidArgumentException(
200 'A public key has not yet been generated using a prior call to generateKeys()'
204 return $this->convert($this->publicKey, self::FORMAT_NUMBER, $format);
208 * Compute the shared secret key based on the public key received from the
209 * the second party to this transaction. This should agree to the secret
210 * key the second party computes on our own public key.
211 * Once in agreement, the key is known to only to both parties.
212 * By default, the function expects the public key to be in binary form
213 * which is the typical format when being transmitted.
215 * If you need the binary form of the shared secret key, call
216 * getSharedSecretKey() with the optional parameter for Binary output.
218 * @param string $publicKey
219 * @param string $publicKeyFormat
220 * @param string $secretKeyFormat
221 * @return string
222 * @throws \Zend\Crypt\Exception\InvalidArgumentException
223 * @throws \Zend\Crypt\Exception\RuntimeException
225 public function computeSecretKey($publicKey, $publicKeyFormat = self::FORMAT_NUMBER,
226 $secretKeyFormat = self::FORMAT_NUMBER)
228 if (function_exists('openssl_dh_compute_key') && static::$useOpenssl !== false) {
229 $publicKey = $this->convert($publicKey, $publicKeyFormat, self::FORMAT_BINARY);
230 $secretKey = openssl_dh_compute_key($publicKey, $this->opensslKeyResource);
231 if (false === $secretKey) {
232 throw new Exception\RuntimeException(
233 'Can not compute key; openssl ' . openssl_error_string()
236 $this->secretKey = $this->convert($secretKey, self::FORMAT_BINARY, self::FORMAT_NUMBER);
237 } else {
238 $publicKey = $this->convert($publicKey, $publicKeyFormat, self::FORMAT_NUMBER);
239 if (!preg_match('/^\d+$/', $publicKey)) {
240 throw new Exception\InvalidArgumentException(
241 'Invalid parameter; not a positive natural number'
244 $this->secretKey = $this->math->powmod($publicKey, $this->getPrivateKey(), $this->getPrime());
247 return $this->getSharedSecretKey($secretKeyFormat);
251 * Return the computed shared secret key from the DiffieHellman transaction
253 * @param string $format
254 * @return string
255 * @throws \Zend\Crypt\Exception\InvalidArgumentException
257 public function getSharedSecretKey($format = self::FORMAT_NUMBER)
259 if (!isset($this->secretKey)) {
260 throw new Exception\InvalidArgumentException(
261 'A secret key has not yet been computed; call computeSecretKey() first'
265 return $this->convert($this->secretKey, self::FORMAT_NUMBER, $format);
269 * Setter for the value of the prime number
271 * @param string $number
272 * @return DiffieHellman
273 * @throws \Zend\Crypt\Exception\InvalidArgumentException
275 public function setPrime($number)
277 if (!preg_match('/^\d+$/', $number) || $number < 11) {
278 throw new Exception\InvalidArgumentException(
279 'Invalid parameter; not a positive natural number or too small: ' .
280 'should be a large natural number prime'
283 $this->prime = (string) $number;
285 return $this;
289 * Getter for the value of the prime number
291 * @param string $format
292 * @return string
293 * @throws \Zend\Crypt\Exception\InvalidArgumentException
295 public function getPrime($format = self::FORMAT_NUMBER)
297 if (!isset($this->prime)) {
298 throw new Exception\InvalidArgumentException('No prime number has been set');
301 return $this->convert($this->prime, self::FORMAT_NUMBER, $format);
306 * Setter for the value of the generator number
308 * @param string $number
309 * @return DiffieHellman
310 * @throws \Zend\Crypt\Exception\InvalidArgumentException
312 public function setGenerator($number)
314 if (!preg_match('/^\d+$/', $number) || $number < 2) {
315 throw new Exception\InvalidArgumentException(
316 'Invalid parameter; not a positive natural number greater than 1'
319 $this->generator = (string) $number;
321 return $this;
325 * Getter for the value of the generator number
327 * @param string $format
328 * @return string
329 * @throws \Zend\Crypt\Exception\InvalidArgumentException
331 public function getGenerator($format = self::FORMAT_NUMBER)
333 if (!isset($this->generator)) {
334 throw new Exception\InvalidArgumentException('No generator number has been set');
337 return $this->convert($this->generator, self::FORMAT_NUMBER, $format);
341 * Setter for the value of the private number
343 * @param string $number
344 * @param string $format
345 * @return DiffieHellman
346 * @throws \Zend\Crypt\Exception\InvalidArgumentException
348 public function setPrivateKey($number, $format = self::FORMAT_NUMBER)
350 $number = $this->convert($number, $format, self::FORMAT_NUMBER);
351 if (!preg_match('/^\d+$/', $number)) {
352 throw new Exception\InvalidArgumentException('Invalid parameter; not a positive natural number');
354 $this->privateKey = (string) $number;
356 return $this;
360 * Getter for the value of the private number
362 * @param string $format
363 * @return string
365 public function getPrivateKey($format = self::FORMAT_NUMBER)
367 if (!$this->hasPrivateKey()) {
368 $this->setPrivateKey($this->generatePrivateKey(), self::FORMAT_BINARY);
371 return $this->convert($this->privateKey, self::FORMAT_NUMBER, $format);
375 * Check whether a private key currently exists.
377 * @return bool
379 public function hasPrivateKey()
381 return isset($this->privateKey);
385 * Convert number between formats
387 * @param $number
388 * @param string $inputFormat
389 * @param string $outputFormat
390 * @return string
392 protected function convert($number, $inputFormat = self::FORMAT_NUMBER,
393 $outputFormat = self::FORMAT_BINARY)
395 if ($inputFormat == $outputFormat) {
396 return $number;
399 // convert to number
400 switch ($inputFormat) {
401 case self::FORMAT_BINARY:
402 case self::FORMAT_BTWOC:
403 $number = $this->math->binToInt($number);
404 break;
405 case self::FORMAT_NUMBER:
406 default:
407 // do nothing
408 break;
411 // convert to output format
412 switch ($outputFormat) {
413 case self::FORMAT_BINARY:
414 return $this->math->intToBin($number);
415 break;
416 case self::FORMAT_BTWOC:
417 return $this->math->intToBin($number, true);
418 break;
419 case self::FORMAT_NUMBER:
420 default:
421 return $number;
422 break;
427 * In the event a private number/key has not been set by the user,
428 * or generated by ext/openssl, a best attempt will be made to
429 * generate a random key. Having a random number generator installed
430 * on linux/bsd is highly recommended! The alternative is not recommended
431 * for production unless without any other option.
433 * @return string
435 protected function generatePrivateKey()
437 return Math\Rand::getBytes(strlen($this->getPrime()), true);