]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - Zend/Crypt/DiffieHellman.php
Release 6.5.0
[Github/sugarcrm.git] / Zend / Crypt / DiffieHellman.php
1 <?php
2 /**
3  * Zend Framework
4  *
5  * LICENSE
6  *
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.
14  *
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
21  */
22
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.
27  *
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
32  */
33 class Zend_Crypt_DiffieHellman
34 {
35
36     /**
37      * Static flag to select whether to use PHP5.3's openssl extension
38      * if available.
39      *
40      * @var boolean
41      */
42     public static $useOpenssl = true;
43
44     /**
45      * Default large prime number; required by the algorithm.
46      *
47      * @var string
48      */
49     private $_prime = null;
50
51     /**
52      * The default generator number. This number must be greater than 0 but
53      * less than the prime number set.
54      *
55      * @var string
56      */
57     private $_generator = null;
58
59     /**
60      * A private number set by the local user. It's optional and will
61      * be generated if not set.
62      *
63      * @var string
64      */
65     private $_privateKey = null;
66
67     /**
68      * BigInteger support object courtesy of Zend_Crypt_Math
69      *
70      * @var Zend_Crypt_Math_BigInteger
71      */
72     private $_math = null;
73
74     /**
75      * The public key generated by this instance after calling generateKeys().
76      *
77      * @var string
78      */
79     private $_publicKey = null;
80
81     /**
82      * The shared secret key resulting from a completed Diffie Hellman
83      * exchange
84      *
85      * @var string
86      */
87     private $_secretKey = null;
88
89     /**
90      * Constants
91      */
92     const BINARY = 'binary';
93     const NUMBER = 'number';
94     const BTWOC  = 'btwoc';
95
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.
100      *
101      * @param string $prime
102      * @param string $generator
103      * @param string $privateKey
104      * @param string $privateKeyType
105      * @return void
106      */
107     public function __construct($prime, $generator, $privateKey = null, $privateKeyType = self::NUMBER)
108     {
109         $this->setPrime($prime);
110         $this->setGenerator($generator);
111         if ($privateKey !== null) {
112             $this->setPrivateKey($privateKey, $privateKeyType);
113         }
114         $this->setBigIntegerMath();
115     }
116
117     /**
118      * Generate own public key. If a private number has not already been
119      * set, one will be generated at this stage.
120      *
121      * @return Zend_Crypt_DiffieHellman
122      */
123     public function generateKeys()
124     {
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();
131             }
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);
140         }
141         return $this;
142     }
143
144     /**
145      * Setter for the value of the public number
146      *
147      * @param string $number
148      * @param string $type
149      * @return Zend_Crypt_DiffieHellman
150      */
151     public function setPublicKey($number, $type = self::NUMBER)
152     {
153         if ($type == self::BINARY) {
154             $number = $this->_math->fromBinary($number);
155         }
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');
159         }
160         $this->_publicKey = (string) $number;
161         return $this;
162     }
163
164     /**
165      * Returns own public key for communication to the second party to this
166      * transaction.
167      *
168      * @param string $type
169      * @return string
170      */
171     public function getPublicKey($type = self::NUMBER)
172     {
173         if ($this->_publicKey === null) {
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()');
176         }
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));
181         }
182         return $this->_publicKey;
183     }
184
185     /**
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.
192      *
193      * If you need the binary form of the shared secret key, call
194      * getSharedSecretKey() with the optional parameter for Binary output.
195      *
196      * @param string $publicKey
197      * @param string $type
198      * @return mixed
199      */
200     public function computeSecretKey($publicKey, $type = self::NUMBER, $output = self::NUMBER)
201     {
202         if ($type == self::BINARY) {
203             $publicKey = $this->_math->fromBinary($publicKey);
204         }
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');
208         }
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());
213         }
214         return $this->getSharedSecretKey($output);
215     }
216
217     /**
218      * Return the computed shared secret key from the DiffieHellman transaction
219      *
220      * @param string $type
221      * @return string
222      */
223     public function getSharedSecretKey($type = self::NUMBER)
224     {
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()');
228         }
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));
233         }
234         return $this->_secretKey;
235     }
236
237     /**
238      * Setter for the value of the prime number
239      *
240      * @param string $number
241      * @return Zend_Crypt_DiffieHellman
242      */
243     public function setPrime($number)
244     {
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');
248         }
249         $this->_prime = (string) $number;
250         return $this;
251     }
252
253     /**
254      * Getter for the value of the prime number
255      *
256      * @return string
257      */
258     public function getPrime()
259     {
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');
263         }
264         return $this->_prime;
265     }
266
267
268     /**
269      * Setter for the value of the generator number
270      *
271      * @param string $number
272      * @return Zend_Crypt_DiffieHellman
273      */
274     public function setGenerator($number)
275     {
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');
279         }
280         $this->_generator = (string) $number;
281         return $this;
282     }
283
284     /**
285      * Getter for the value of the generator number
286      *
287      * @return string
288      */
289     public function getGenerator()
290     {
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');
294         }
295         return $this->_generator;
296     }
297
298     /**
299      * Setter for the value of the private number
300      *
301      * @param string $number
302      * @param string $type
303      * @return Zend_Crypt_DiffieHellman
304      */
305     public function setPrivateKey($number, $type = self::NUMBER)
306     {
307         if ($type == self::BINARY) {
308             $number = $this->_math->fromBinary($number);
309         }
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');
313         }
314         $this->_privateKey = (string) $number;
315         return $this;
316     }
317
318     /**
319      * Getter for the value of the private number
320      *
321      * @param string $type
322      * @return string
323      */
324     public function getPrivateKey($type = self::NUMBER)
325     {
326         if (!$this->hasPrivateKey()) {
327             $this->setPrivateKey($this->_generatePrivateKey(), self::BINARY);
328         }
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));
333         }
334         return $this->_privateKey;
335     }
336
337     /**
338      * Check whether a private key currently exists.
339      *
340      * @return boolean
341      */
342     public function hasPrivateKey()
343     {
344         return isset($this->_privateKey);
345     }
346
347     /**
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.
352      *
353      * @param string $extension
354      * @return void
355      */
356     public function setBigIntegerMath($extension = null)
357     {
358         /**
359          * @see Zend_Crypt_Math
360          */
361         require_once 'Zend/Crypt/Math.php';
362         $this->_math = new Zend_Crypt_Math($extension);
363     }
364
365     /**
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.
371      *
372      * @return string
373      */
374     protected function _generatePrivateKey()
375     {
376         $rand = $this->_math->rand($this->getGenerator(), $this->getPrime());
377         return $rand;
378     }
379
380 }