web/Zend/Crypt/DiffieHellman.php
changeset 0 4eba9c11703f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/Zend/Crypt/DiffieHellman.php	Mon Dec 13 18:29:26 2010 +0100
@@ -0,0 +1,380 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Crypt
+ * @subpackage DiffieHellman
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: DiffieHellman.php 22662 2010-07-24 17:37:36Z mabe $
+ */
+
+/**
+ * PHP implementation of the Diffie-Hellman public key encryption algorithm.
+ * Allows two unassociated parties to establish a joint shared secret key
+ * to be used in encrypting subsequent communications.
+ *
+ * @category   Zend
+ * @package    Zend_Crypt
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Crypt_DiffieHellman
+{
+
+    /**
+     * Static flag to select whether to use PHP5.3's openssl extension
+     * if available.
+     *
+     * @var boolean
+     */
+    public static $useOpenssl = true;
+
+    /**
+     * Default large prime number; required by the algorithm.
+     *
+     * @var string
+     */
+    private $_prime = null;
+
+    /**
+     * The default generator number. This number must be greater than 0 but
+     * less than the prime number set.
+     *
+     * @var string
+     */
+    private $_generator = null;
+
+    /**
+     * A private number set by the local user. It's optional and will
+     * be generated if not set.
+     *
+     * @var string
+     */
+    private $_privateKey = null;
+
+    /**
+     * BigInteger support object courtesy of Zend_Crypt_Math
+     *
+     * @var Zend_Crypt_Math_BigInteger
+     */
+    private $_math = null;
+
+    /**
+     * The public key generated by this instance after calling generateKeys().
+     *
+     * @var string
+     */
+    private $_publicKey = null;
+
+    /**
+     * The shared secret key resulting from a completed Diffie Hellman
+     * exchange
+     *
+     * @var string
+     */
+    private $_secretKey = null;
+
+    /**
+     * Constants
+     */
+    const BINARY = 'binary';
+    const NUMBER = 'number';
+    const BTWOC  = 'btwoc';
+
+    /**
+     * Constructor; if set construct the object using the parameter array to
+     * set values for Prime, Generator and Private.
+     * If a Private Key is not set, one will be generated at random.
+     *
+     * @param string $prime
+     * @param string $generator
+     * @param string $privateKey
+     * @param string $privateKeyType
+     * @return void
+     */
+    public function __construct($prime, $generator, $privateKey = null, $privateKeyType = self::NUMBER)
+    {
+        $this->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;
+    }
+
+}