add methods to decrypt return data from router
[GitHub/Stricted/speedport-hybrid-php-api.git] / CryptLib / Random / Generator.php
diff --git a/CryptLib/Random/Generator.php b/CryptLib/Random/Generator.php
new file mode 100644 (file)
index 0000000..b5509fa
--- /dev/null
@@ -0,0 +1,186 @@
+<?php
+/**
+ * The Random Number Generator Class
+ *
+ * Use this factory to generate cryptographic quality random numbers (strings)
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Timo Hamina
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random;
+
+use CryptLib\Core\BaseConverter;
+
+/**
+ * The Random Number Generator Class
+ *
+ * Use this factory to generate cryptographic quality random numbers (strings)
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Timo Hamina
+ */
+class Generator {
+
+    /**
+     * @var Mixer The mixing strategy to use for this generator instance
+     */
+    protected $mixer = null;
+
+    /**
+     * @var array An array of random number sources to use for this generator
+     */
+    protected $sources = array();
+
+    /**
+     * Build a new instance of the generator
+     *
+     * @param array $sources An array of random data sources to use
+     * @param Mixer $mixer   The mixing strategy to use for this generator
+     */
+    public function __construct(array $sources, Mixer $mixer) {
+        foreach ($sources as $source) {
+            $this->addSource($source);
+        }
+        $this->mixer = $mixer;
+    }
+
+    /**
+     * Add a random number source to the generator
+     *
+     * @param Source $source The random number source to add
+     *
+     * @return Generator $this The current generator instance
+     */
+    public function addSource(Source $source) {
+        $this->sources[] = $source;
+        return $this;
+    }
+
+    /**
+     * Generate a random number (string) of the requested size
+     *
+     * @param int $size The size of the requested random number
+     *
+     * @return string The generated random number (string)
+     */
+    public function generate($size) {
+        $seeds = array();
+        foreach ($this->sources as $source) {
+            $seeds[] = $source->generate($size);
+        }
+        return $this->mixer->mix($seeds);
+    }
+
+    /**
+     * Generate a random integer with the given range
+     *
+     * @param int $min The lower bound of the range to generate
+     * @param int $max The upper bound of the range to generate
+     *
+     * @return int The generated random number within the range
+     */
+    public function generateInt($min = 0, $max = PHP_INT_MAX) {
+        $tmp   = (int) max($max, $min);
+        $min   = (int) min($max, $min);
+        $max   = $tmp;
+        $range = $max - $min;
+        if ($range == 0) {
+            return $max;
+        } elseif ($range > PHP_INT_MAX || is_float($range)) {
+            /**
+             * This works, because PHP will auto-convert it to a float at this point,
+             * But on 64 bit systems, the float won't have enough precision to
+             * actually store the difference, so we need to check if it's a float
+             * and hence auto-converted...
+             */
+            throw new \RangeException(
+                'The supplied range is too great to generate'
+            );
+        }
+
+        $bits  = (int) floor(log($range, 2) + 1);
+        $bytes = (int) max(ceil($bits / 8), 1);
+        $mask  = (int) (pow(2, $bits) - 1);
+        /**
+         * The mask is a better way of dropping unused bits.  Basically what it does
+         * is to set all the bits in the mask to 1 that we may need.  Since the max
+         * range is PHP_INT_MAX, we will never need negative numbers (which would
+         * have the MSB set on the max int possible to generate).  Therefore we
+         * can just mask that away.  Since pow returns a float, we need to cast
+         * it back to an int so the mask will work.
+         *
+         * On a 64 bit platform, that means that PHP_INT_MAX is 2^63 - 1.  Which
+         * is also the mask if 63 bits are needed (by the log(range, 2) call).
+         * So if the computed result is negative (meaning the 64th bit is set), the
+         * mask will correct that.
+         *
+         * This turns out to be slightly better than the shift as we don't need to
+         * worry about "fixing" negative values.
+         */
+        do {
+            $test   = $this->generate($bytes);
+            $result = hexdec(bin2hex($test)) & $mask;
+        } while ($result > $range);
+        return $result + $min;
+    }
+
+    /**
+     * Generate a random string of specified length.
+     *
+     * This uses the supplied character list for generating the new result
+     * string.
+     *
+     * @param int    $length     The length of the generated string
+     * @param string $characters An optional list of characters to use
+     *
+     * @return string The generated random string
+     */
+    public function generateString($length, $characters = '') {
+        if ($length == 0 || strlen($characters) == 1) {
+            return '';
+        } elseif (empty($characters)) {
+            // Default to base 64
+            $characters = '0123456789abcdefghijklmnopqrstuvwxyz' .
+                          'ABCDEFGHIJKLMNOPQRSTUVWXYZ./';
+        }
+        //determine how many bytes to generate
+        $bytes  = ceil($length * floor(log(strlen($characters), 2) + 1.01) / 8);
+        $rand   = $this->generate($bytes);
+        $result = BaseConverter::convertFromBinary($rand, $characters);
+        if (strlen($result) < $length) {
+            $result = str_pad($result, $length, $characters[0], STR_PAD_LEFT);
+        } else {
+            $result = substr($result, 0, $length);
+        }
+        return $result;
+    }
+
+    /**
+     * Get the Mixer used for this instance
+     *
+     * @return Mixer the current mixer
+     */
+    public function getMixer() {
+        return $this->mixer;
+    }
+
+    /**
+     * Get the Sources used for this instance
+     *
+     * @return Source[] the current mixer
+     */
+    public function getSources() {
+        return $this->sources;
+    }
+
+}