add methods to decrypt return data from router
authorStricted <info@stricted.de>
Wed, 1 Jul 2015 04:36:25 +0000 (06:36 +0200)
committerStricted <info@stricted.de>
Wed, 1 Jul 2015 04:36:25 +0000 (06:36 +0200)
86 files changed:
CryptLib/Cipher/Block/AbstractCipher.php [new file with mode: 0644]
CryptLib/Cipher/Block/AbstractMode.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher/AES.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher/DES.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher/MCrypt.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher/Rijndael.php [new file with mode: 0644]
CryptLib/Cipher/Block/Cipher/TripleDES.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/CBC.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/CCM.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/CFB.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/CTR.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/ECB.php [new file with mode: 0644]
CryptLib/Cipher/Block/Mode/NOFB.php [new file with mode: 0644]
CryptLib/Cipher/Factory.php [new file with mode: 0644]
CryptLib/Core/AbstractFactory.php [new file with mode: 0644]
CryptLib/Core/AutoLoader.php [new file with mode: 0644]
CryptLib/Core/BaseConverter.php [new file with mode: 0644]
CryptLib/Core/BigMath.php [new file with mode: 0644]
CryptLib/Core/BigMath/BCMath.php [new file with mode: 0644]
CryptLib/Core/BigMath/GMP.php [new file with mode: 0644]
CryptLib/Core/BigMath/PHPMath.php [new file with mode: 0644]
CryptLib/Core/Enum.php [new file with mode: 0644]
CryptLib/Core/Strength.php [new file with mode: 0644]
CryptLib/CryptLib.php [new file with mode: 0644]
CryptLib/Encryption/Factory.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode/ANSIx923.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode/ISO10126.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode/None.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode/PKCS7.php [new file with mode: 0644]
CryptLib/Encryption/PackingMode/Zeros.php [new file with mode: 0644]
CryptLib/Hash/CRC32.php [new file with mode: 0644]
CryptLib/Hash/Hash.php [new file with mode: 0644]
CryptLib/Key/Derivation/AbstractDerivation.php [new file with mode: 0644]
CryptLib/Key/Derivation/KDF.php [new file with mode: 0644]
CryptLib/Key/Derivation/KDF/KDF1.php [new file with mode: 0644]
CryptLib/Key/Derivation/KDF/KDF2.php [new file with mode: 0644]
CryptLib/Key/Derivation/KDF/KDF3.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/BCrypt.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/PBKDF1.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/PBKDF2.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/SHA256.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/SHA512.php [new file with mode: 0644]
CryptLib/Key/Derivation/PBKDF/Schneier.php [new file with mode: 0644]
CryptLib/Key/Factory.php [new file with mode: 0644]
CryptLib/Key/Generator.php [new file with mode: 0644]
CryptLib/Key/Key.php [new file with mode: 0644]
CryptLib/Key/Symmetric.php [new file with mode: 0644]
CryptLib/Key/Symmetric/AbstractSymmetric.php [new file with mode: 0644]
CryptLib/Key/Symmetric/Generator/Internal.php [new file with mode: 0644]
CryptLib/Key/Symmetric/Raw.php [new file with mode: 0644]
CryptLib/MAC/AbstractMAC.php [new file with mode: 0644]
CryptLib/MAC/Implementation/CMAC.php [new file with mode: 0644]
CryptLib/MAC/Implementation/HMAC.php [new file with mode: 0644]
CryptLib/MAC/MAC.php [new file with mode: 0644]
CryptLib/Password/Factory.php [new file with mode: 0644]
CryptLib/Password/Implementation/APR1.php [new file with mode: 0644]
CryptLib/Password/Implementation/Blowfish.php [new file with mode: 0644]
CryptLib/Password/Implementation/Drupal.php [new file with mode: 0644]
CryptLib/Password/Implementation/Hash.php [new file with mode: 0644]
CryptLib/Password/Implementation/Joomla.php [new file with mode: 0644]
CryptLib/Password/Implementation/PBKDF.php [new file with mode: 0644]
CryptLib/Password/Implementation/PHPASS.php [new file with mode: 0644]
CryptLib/Password/Implementation/PHPBB.php [new file with mode: 0644]
CryptLib/Password/Password.php [new file with mode: 0644]
CryptLib/Random/AbstractMixer.php [new file with mode: 0644]
CryptLib/Random/Factory.php [new file with mode: 0644]
CryptLib/Random/Generator.php [new file with mode: 0644]
CryptLib/Random/Mixer.php [new file with mode: 0644]
CryptLib/Random/Mixer/DES.php [new file with mode: 0644]
CryptLib/Random/Mixer/Hash.php [new file with mode: 0644]
CryptLib/Random/Mixer/Rijndael.php [new file with mode: 0644]
CryptLib/Random/Source.php [new file with mode: 0644]
CryptLib/Random/Source/CAPICOM.php [new file with mode: 0644]
CryptLib/Random/Source/MTRand.php [new file with mode: 0644]
CryptLib/Random/Source/MicroTime.php [new file with mode: 0644]
CryptLib/Random/Source/OpenSSL.php [new file with mode: 0644]
CryptLib/Random/Source/Rand.php [new file with mode: 0644]
CryptLib/Random/Source/Random.php [new file with mode: 0644]
CryptLib/Random/Source/URandom.php [new file with mode: 0644]
CryptLib/Random/Source/UniqID.php [new file with mode: 0644]
CryptLib/bootstrap.php [new file with mode: 0644]
speedport.class.php

diff --git a/CryptLib/Cipher/Block/AbstractCipher.php b/CryptLib/Cipher/Block/AbstractCipher.php
new file mode 100644 (file)
index 0000000..7df8ad5
--- /dev/null
@@ -0,0 +1,217 @@
+<?php
+/**
+ * An abstract class for simplifing creation of ciphers
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block;
+
+/**
+ * An abstract class for simplifing creation of ciphers
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ */
+abstract class AbstractCipher implements \CryptLib\Cipher\Block\Cipher {
+
+    /**
+     * @var int The block size for the cipher
+     */
+    protected $blockSize = 0;
+
+    /**
+     * @var string The cipher name for the current instance
+     */
+    protected $cipher = '';
+
+    /**
+     * @var boolean Is the cipher ready to encrypt/decrypt
+     */
+    protected $initialized = false;
+
+    /**
+     * @var string The key to use for encryption/decryption
+     */
+    protected $key = '';
+
+    /**
+     * @var int The size of the key to use
+     */
+    protected $keySize = 0;
+
+    /**
+     * Decrypt a block of data
+     * 
+     * @param string $data The ciphertext to decrypt
+     * 
+     * @return string The decrypted data
+     */
+    abstract protected function decryptBlockData($data);
+
+    /**
+     * Encrypt a block of data
+     * 
+     * @param string $data The plaintext to encrypt
+     * 
+     * @return string The encrypted cipher text
+     */
+    abstract protected function encryptBlockData($data);
+
+    /**
+     * Construct the instance for the supplied cipher name
+     *
+     * @param string $cipher The cipher to implement
+     *
+     * @return void
+     * @throws InvalidArgumentException if the cipher is not supported
+     */
+    public function __construct($cipher) {
+        $ciphers = static::getSupportedCiphers();
+        if (in_array($cipher, $ciphers)) {
+            $this->cipher = $cipher;
+        } else {
+            throw new \InvalidArgumentException('Unsupported Cipher Supplied');
+        }
+    }
+
+    /**
+     * Decrypt a block of data using the supplied string key.
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     * @throws InvalidArgumentException If the data size is not the block size
+     * @throws RuntimeException If the cipher is not initialized
+     */
+    public function decryptBlock($data) {
+        $this->enforceInitializedCipher();
+        $this->enforceProperBlockSize($data);
+        return $this->decryptBlockData($data);
+    }
+
+    /**
+     * Encrypt a block of data using the supplied string key.
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     * @throws InvalidArgumentException If the data size is not the block size
+     * @throws RuntimeException If the cipher is not initialized
+     */
+    public function encryptBlock($data) {
+        $this->enforceInitializedCipher();
+        $this->enforceProperBlockSize($data);
+        return $this->encryptBlockData($data);
+    }
+
+    /**
+     * Get the block size for the current initialized cipher
+     *
+     * @param string $key The key the data will be encrypted with
+     *
+     * @return int The block size for the current cipher
+     */
+    public function getBlockSize() {
+        return $this->blockSize;
+    }
+
+    /**
+     * Get the string name of the current cipher instance
+     *
+     * @return string The current instantiated cipher
+     */
+    public function getCipher() {
+        return $this->cipher;
+    }
+
+    /**
+     * Get the key size for the current initialized cipher
+     * 
+     * @return int The key size for the current cipher
+     */
+    public function getKeySize() {
+        return $this->keySize;
+    }
+
+    /**
+     * Set the key to use for the cipher
+     *
+     * @param string $key The key to use
+     * 
+     * @throws InvalidArgumentException If the key is not the correct size
+     * @return void
+     */
+    public function setKey($key) {
+        if (strlen($key) != $this->getKeySize()) {
+            throw new \InvalidArgumentException(
+                sprintf(
+                    'The supplied key block is not the correct size [%d:%d]',
+                    strlen($key),
+                    $this->getKeySize()
+                )
+            );
+        }
+        $this->key         = $key;
+        $this->initialized = $this->initialize();
+    }
+
+    /**
+     * Check to see if the cipher is initialized
+     * 
+     * @return void
+     * @throws RuntimeException If the cipher is not initialized
+     */
+    protected function enforceInitializedCipher() {
+        if (!$this->initialized) {
+            throw new \RuntimeException(
+                'The cipher has not been properly initialized'
+            );
+        }
+    }
+
+    /**
+     * Check to see if the data is of the correct block size
+     *
+     * @param string $data The data block to check
+     * 
+     * @return void
+     * @throws InvalidArgumentException if the data is not the correct size
+     */
+    protected function enforceProperBlockSize($data) {
+        if (strlen($data) != $this->getBlockSize()) {
+            throw new \InvalidArgumentException(
+                sprintf(
+                    'The supplied data block is not the correct size [%d:%d]',
+                    strlen($data),
+                    $this->getBlockSize()
+                )
+            );
+        }
+    }
+
+    /**
+     * Initialize the function after the key is set
+     *
+     * @return boolean The status of the initialization
+     */
+    protected function initialize() {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Cipher/Block/AbstractMode.php b/CryptLib/Cipher/Block/AbstractMode.php
new file mode 100644 (file)
index 0000000..5bdef45
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+/**
+ * An abstract class for simplifing creation of cipher modes
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block;
+
+/**
+ * An abstract class for simplifing creation of cipher modes
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ */
+abstract class AbstractMode implements \CryptLib\Cipher\Block\Mode {
+
+    /**
+     * @var string Additional data to authenticate with
+     */
+    protected $adata = '';
+
+    /**
+     * @var Cipher The cipher to use for this mode instance
+     */
+    protected $cipher = null;
+
+    /**
+     * @var string The initialization Vector to use for this mode
+     */
+    protected $initv = '';
+
+    /**
+     * @var string The mode name for the current instance
+     */
+    protected $mode = '';
+
+    /**
+     * @var array Mode specific options
+     */
+    protected $options = array();
+
+    /**
+     * @var string The internal state of the mode
+     */
+    protected $state = '';
+
+    /**
+     * Perform the decryption of the current block
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    abstract protected function decryptBlock($data);
+
+    /**
+     * Perform the encryption of the current block
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    abstract protected function encryptBlock($data);
+
+    /**
+     * Build the instance of the cipher mode
+     *
+     * @param Cipher $cipher  The cipher to use for encryption/decryption
+     * @param string $initv   The initialization vector (empty if not needed)
+     * @param array  $options An array of mode-specific options
+     */
+    public function __construct(
+        \CryptLib\Cipher\Block\Cipher $cipher,
+        $initv,
+        array $options = array()
+    ) {
+        $class         = strtolower(get_class($this));
+        $class         = substr($class, strrpos($class, '\\') + 1);
+        $this->mode    = $class;
+        $this->options = $options + $this->options;
+        $this->cipher  = $cipher;
+        $this->initv   = $initv;
+        $this->reset();
+    }
+
+    /**
+     * Decrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    public function decrypt($data) {
+        $this->enforceBlockSize($data);
+        return $this->decryptBlock($data);
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    public function encrypt($data) {
+        $this->enforceBlockSize($data);
+        return $this->encryptBlock($data);
+    }
+
+    /**
+     * Finish the mode and append any additional data necessary
+     *
+     * @return string Any additional data
+     */
+    public function finish() {
+        return '';
+    }
+
+    /**
+     * Get the name of the current mode implementation
+     *
+     * @return string The current mode name
+     */
+    public function getMode() {
+        return $this->mode;
+    }
+
+    /**
+     * Reset the mode to start over (destroying any intermediate state)
+     *
+     * @return void
+     */
+    public function reset() {
+        $this->state = $this->initv;
+    }
+
+    /**
+     * Enforce the data block is the correct size for the cipher
+     *
+     * @param string $data The data to check
+     *
+     * @return void
+     * @throws InvalidArgumentException if the block size is not correct
+     */
+    protected function enforceBlockSize($data) {
+        if (strlen($data) != $this->cipher->getBlockSize()) {
+            throw new \InvalidArgumentException(
+                sprintf(
+                    'The data block must match the block size [%d:%d]',
+                    strlen($data),
+                    $this->cipher->getBlockSize()
+                )
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/CryptLib/Cipher/Block/Cipher.php b/CryptLib/Cipher/Block/Cipher.php
new file mode 100644 (file)
index 0000000..e250ab5
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/**
+ * The interface that all block ciphers must implement
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block;
+
+/**
+ * The interface that all block ciphers must implement
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface Cipher {
+
+    /**
+     * Get a list of supported ciphers by this cipher.
+     *
+     * @return array An array of supported cipher names (strings)
+     */
+    public static function getSupportedCiphers();
+
+    /**
+     * Decrypt a block of data using the supplied string key.
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     */
+    public function decryptBlock($data);
+
+    /**
+     * Encrypt a block of data using the supplied string key.
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     */
+    public function encryptBlock($data);
+
+    /**
+     * Get the block size for the current initialized cipher.
+     *
+     * @return int The block size for the current cipher
+     */
+    public function getBlockSize();
+
+    /**
+     * Get the key size for the current initialized cipher
+     * 
+     * @return int The key size for the current cipher
+     */
+    public function getKeySize();
+
+    /**
+     * Get the string name of the current cipher instance.
+     *
+     * @return string The current instantiated cipher
+     */
+    public function getCipher();
+
+    /**
+     * Set the key to be used in this instance
+     * 
+     * @param string $key The key the data will be encrypted with
+     * 
+     * @return void
+     */
+    public function setKey($key);
+
+}
diff --git a/CryptLib/Cipher/Block/Cipher/AES.php b/CryptLib/Cipher/Block/Cipher/AES.php
new file mode 100644 (file)
index 0000000..41d9785
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * An implementation of the AES cipher, using the phpseclib implementation
+ * 
+ * This was forked from phpseclib and modified to use CryptLib conventions
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Jim Wigginton <terrafrost@php.net>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Cipher;
+
+/**
+ * An implementation of the AES cipher, using the phpseclib implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class AES extends Rijndael {
+
+    /**
+     * Get a list of supported ciphers for this class implementation
+     *
+     * @return array A list of supported ciphers
+     */
+    public static function getSupportedCiphers() {
+        return array(
+            'aes-128',
+            'aes-192',
+            'aes-256',
+        );
+    }
+
+    /**
+     * Construct the instance for the supplied cipher name
+     *
+     * @param string $cipher The cipher to implement
+     *
+     * @return void
+     * @throws InvalidArgumentException if the cipher is not supported
+     */
+    public function __construct($cipher) {
+        parent::__construct($cipher);
+        list (, $bits) = explode('-', $cipher, 2);
+        $this->setBlockSize(128);
+        $this->setKeySize($bits);
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Cipher/DES.php b/CryptLib/Cipher/Block/Cipher/DES.php
new file mode 100644 (file)
index 0000000..9d8c027
--- /dev/null
@@ -0,0 +1,396 @@
+<?php
+/**
+ * An implementation of the DES cipher, using the phpseclib implementation
+ * 
+ * This was forked from phpseclib and modified to use CryptLib conventions
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Jim Wigginton <terrafrost@php.net>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Cipher;
+
+/**
+ * An implementation of the DES cipher, using the phpseclib implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class DES extends \CryptLib\Cipher\Block\AbstractCipher {
+
+    /**
+     * @var int The block size for the cipher
+     */
+    protected $blockSize = 8;
+
+    /**
+     * @var int The key size for the cipher
+     */
+    protected $keySize = 8;
+
+    /**
+     * @var array The prepared key schedule
+     */
+    protected $preparedKeys = array();
+
+    /**
+     * In the official DES docs, they're described as being matrices that one 
+     * accesses by using the first and last bits to determine the row and the 
+     * middle four bits to determine the column.  in this implementation, 
+     * they've been converted to vectors
+     * 
+     * @var array The S-boxes
+     */
+    protected static $sbox = array(
+        array(
+            14,  0,  4, 15, 13,  7,  1,  4,  2, 14, 15,  2, 11, 13,  8,  1,
+             3, 10 ,10,  6,  6, 12, 12, 11,  5,  9,  9,  5,  0,  3,  7,  8,
+             4, 15,  1, 12, 14,  8,  8,  2, 13,  4,  6,  9,  2,  1, 11,  7,
+            15,  5, 12, 11,  9,  3,  7, 14,  3, 10, 10,  0,  5,  6,  0, 13
+        ),
+        array(
+            15,  3,  1, 13,  8,  4, 14,  7,  6, 15, 11,  2,  3,  8,  4, 14,
+             9, 12,  7,  0,  2,  1, 13, 10, 12,  6,  0,  9,  5, 11, 10,  5,
+             0, 13, 14,  8,  7, 10, 11,  1, 10,  3,  4, 15, 13,  4,  1,  2,
+             5, 11,  8,  6, 12,  7,  6, 12,  9,  0,  3,  5,  2, 14, 15,  9
+        ),
+        array(
+            10, 13,  0,  7,  9,  0, 14,  9,  6,  3,  3,  4, 15,  6,  5, 10,
+             1,  2, 13,  8, 12,  5,  7, 14, 11, 12,  4, 11,  2, 15,  8,  1,
+            13,  1,  6, 10,  4, 13,  9,  0,  8,  6, 15,  9,  3,  8,  0,  7,
+            11,  4,  1, 15,  2, 14, 12,  3,  5, 11, 10,  5, 14,  2,  7, 12
+        ),
+        array(
+             7, 13, 13,  8, 14, 11,  3,  5,  0,  6,  6, 15,  9,  0, 10,  3,
+             1,  4,  2,  7,  8,  2,  5, 12, 11,  1, 12, 10,  4, 14, 15,  9,
+            10,  3,  6, 15,  9,  0,  0,  6, 12, 10, 11,  1,  7, 13, 13,  8,
+            15,  9,  1,  4,  3,  5, 14, 11,  5, 12,  2,  7,  8,  2,  4, 14
+        ),
+        array(
+             2, 14, 12, 11,  4,  2,  1, 12,  7,  4, 10,  7, 11, 13,  6,  1,
+             8,  5,  5,  0,  3, 15, 15, 10, 13,  3,  0,  9, 14,  8,  9,  6,
+             4, 11,  2,  8,  1, 12, 11,  7, 10,  1, 13, 14,  7,  2,  8, 13,
+            15,  6,  9, 15, 12,  0,  5,  9,  6, 10,  3,  4,  0,  5, 14,  3
+        ),
+        array(
+            12, 10,  1, 15, 10,  4, 15,  2,  9,  7,  2, 12,  6,  9,  8,  5,
+             0,  6, 13,  1,  3, 13,  4, 14, 14,  0,  7, 11,  5,  3, 11,  8,
+             9,  4, 14,  3, 15,  2,  5, 12,  2,  9,  8,  5, 12, 15,  3, 10,
+             7, 11,  0, 14,  4,  1, 10,  7,  1,  6, 13,  0, 11,  8,  6, 13
+        ),
+        array(
+             4, 13, 11,  0,  2, 11, 14,  7, 15,  4,  0,  9,  8,  1, 13, 10,
+             3, 14, 12,  3,  9,  5,  7, 12,  5,  2, 10, 15,  6,  8,  1,  6,
+             1,  6,  4, 11, 11, 13, 13,  8, 12,  1,  3,  4,  7, 10, 14,  7,
+            10,  9, 15,  5,  6,  0,  8, 15,  0, 14,  5,  2,  9,  3,  2, 12
+        ),
+        array(
+            13,  1,  2, 15,  8, 13,  4,  8,  6, 10, 15,  3, 11,  7,  1,  4,
+            10, 12,  9,  5,  3,  6, 14, 11,  5,  0,  0, 14, 12,  9,  7,  2,
+             7,  2, 11,  1,  4, 14,  1,  7,  9,  4, 12, 10, 14,  8,  2, 13,
+             0, 15,  6, 12, 10,  9, 13,  0, 15,  3,  3,  5,  5,  6,  8, 11
+        )
+    );
+
+    /**
+     * @var array The key shift sequence for shifts per round of DES block
+     */
+    protected static $keyShifts = array(
+        1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+    );
+
+    /**
+     * Get a list of supported ciphers for this class implementation
+     *
+     * @return array A list of supported ciphers
+     */
+    public static function getSupportedCiphers() {
+        return array('des');
+    }
+
+    /**
+     * Decrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     */
+    protected function decryptBlockData($data) {
+        $keys = array_reverse($this->preparedKeys);
+        return $this->processBlock($data, $keys);
+    }
+
+    /**
+     * Encrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     */
+    protected function encryptBlockData($data) {
+        return $this->processBlock($data, $this->preparedKeys);
+    }
+
+    /**
+     * Initialize the cipher by preparing the key
+     *
+     * @return boolean The status of the initialization
+     */
+    protected function initialize() {
+        $this->preparedKeys = $this->prepareKey($this->key);
+        return true;
+    }
+
+    /**
+     * Compute the keys necessary to execute the block cipher
+     *
+     * @param string $key The key to prepare
+     * 
+     * @return array The prepared keys
+     */
+    private function prepareKey($key) {
+        // pad the key and remove extra characters as appropriate.
+        $key = str_pad(substr($key, 0, 8), 8, chr(0));
+
+        $temp    = unpack('Na/Nb', $key);
+        $key     = array($temp['a'], $temp['b']);
+        $msb     = array(
+            ($key[0] >> 31) & 1,
+            ($key[1] >> 31) & 1
+        );
+        $key[0] &= 0x7FFFFFFF;
+        $key[1] &= 0x7FFFFFFF;
+
+        $key = array(
+            (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
+            (($key[1] & 0x00020408) <<  8) | (($key[1] & 0x02040800) >>  1) |
+            (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
+            (($key[0] & 0x00020408) <<  4) | (($key[0] & 0x02040800) >>  5) |
+            (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
+            (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
+            (($key[0] & 0x00000010) >>  1) | (($key[0] & 0x00001000) >> 10) |
+            (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28),
+            (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
+            (($key[1] & 0x00800000) <<  2) | (($key[0] & 0x00000080) << 16) |
+            (($key[0] & 0x00008000) <<  7) | (($key[0] & 0x00800000) >>  2) |
+            (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) <<  4) |
+            (($key[1] & 0x00400000) >>  5) | (($key[1] & 0x40000000) >> 14) |
+            (($key[0] & 0x00000040) <<  9) | ( $key[0] & 0x00004000       ) |
+            (($key[0] & 0x00400000) >>  9) | (($key[0] & 0x40000000) >> 18) |
+            (($key[1] & 0x00000020) <<  6) | (($key[1] & 0x00002000) >>  3) |
+            (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
+            (($key[0] & 0x00000020) <<  2) | (($key[0] & 0x00002000) >>  7) |
+            (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
+            (($key[1] & 0x00000010) >>  1) | (($key[1] & 0x00001000) >> 10) |
+            (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
+            ($msb[1] << 24) | ($msb[0] << 20)
+        );
+
+        $keys = array();
+        for ($i = 0; $i < 16; $i++) {
+            $key[0] <<= static::$keyShifts[$i];
+            $temp   = ($key[0] & 0xF0000000) >> 28;
+            $key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
+
+            $key[1] <<= static::$keyShifts[$i];
+            $temp   = ($key[1] & 0xF0000000) >> 28;
+            $key[1] = ($key[1] | $temp) & 0x0FFFFFFF;
+
+            $temp = array(
+                (($key[1] & 0x00004000) >>  9) | (($key[1] & 0x00000800) >>  7) |
+                (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >>  2) |
+                (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23),
+                (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) <<  4) |
+                (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) |
+                (($key[1] & 0x00000080) >>  6),
+                ( $key[1] & 0x00000020       ) | (($key[1] & 0x00000200) >>  5) |
+                (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) |
+                (($key[1] & 0x00000004) >>  1) | (($key[1] & 0x00100000) >> 20),
+                (($key[1] & 0x00001000) >>  7) | (($key[1] & 0x00200000) >> 17) |
+                (($key[1] & 0x00000002) <<  2) | (($key[1] & 0x00000100) >>  6) |
+                (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26),
+                (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010       ) |
+                (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) |
+                (($key[0] & 0x00000200) >>  8) | (($key[0] & 0x00000002) >>  1),
+                (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) |
+                (($key[0] & 0x00000020) >>  2) | (($key[0] & 0x00000800) >>  9) |
+                (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >>  8),
+                (($key[0] & 0x00001000) >>  7) | (($key[0] & 0x00000088) >>  3) |
+                (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) <<  2) |
+                (($key[0] & 0x00400000) >> 21),
+                (($key[0] & 0x00000400) >>  5) | (($key[0] & 0x00004000) >> 10) |
+                (($key[0] & 0x00000040) >>  3) | (($key[0] & 0x00100000) >> 18) |
+                (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24)
+            );
+
+            $keys[] = $temp;
+        }
+
+        return $keys;
+    }
+
+    /**
+     * Process a block of data and encrypt (or decrypt depending upon key sequence)
+     *
+     * @param string $block The block of data to process
+     * @param array  $keys  The array of prepared keys to use
+     * 
+     * @return string The processed block data
+     */
+    protected function processBlock($block, array $keys) {
+        $temp  = unpack('Na/Nb', $block);
+        $block = array($temp['a'], $temp['b']);
+
+        /**
+         * Because php does arithmetic right shifts, if the most significant bits
+         * are set, right shifting those into the correct position will add 1's -
+         * not 0's.  this will intefere with the | operation unless a second & is
+         * done.  so we isolate these bits and left shift them into place.  we
+         * then & each block with 0x7FFFFFFF to prevennt 1's from being added for
+         * any other shifts.
+         */
+        $msb       = array(
+            ($block[0] >> 31) & 1,
+            ($block[1] >> 31) & 1
+        );
+        $block[0] &= 0x7FFFFFFF;
+        $block[1] &= 0x7FFFFFFF;
+
+        /**
+         * We isolate the appropriate bit in the appropriate integer and shift as
+         * appropriate. In some cases, there are going to be multiple bits in the
+         * same integer that need to be shifted in the same way.  we combine those
+         * into one shift operation.
+         */
+        $block = array(
+            (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
+            (($block[1] & 0x00400001) <<  7) | (($block[1] & 0x40000100) >>  2) |
+            (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
+            (($block[0] & 0x00400001) <<  3) | (($block[0] & 0x40000100) >>  6) |
+            (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
+            (($block[1] & 0x00100000) <<  1) | (($block[1] & 0x10000000) >>  8) |
+            (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) <<  6) |
+            (($block[0] & 0x00100000) >>  3) | (($block[0] & 0x10000000) >> 12) |
+            (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) <<  4) |
+            (($block[1] & 0x00040000) >>  5) | (($block[1] & 0x04000000) >> 14) |
+            (($block[0] & 0x00000004) <<  9) | ( $block[0] & 0x00000400       ) |
+            (($block[0] & 0x00040000) >>  9) | (($block[0] & 0x04000000) >> 18) |
+            (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
+            (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24),
+            (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
+            (($block[1] & 0x00800002) <<  6) | (($block[0] & 0x00000080) << 20) |
+            (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) <<  2) |
+            (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) <<  9) |
+            ( $block[1] & 0x00200000       ) | (($block[1] & 0x20000000) >>  9) |
+            (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) <<  5) |
+            (($block[0] & 0x00200000) >>  4) | (($block[0] & 0x20000000) >> 13) |
+            (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) <<  3) |
+            (($block[1] & 0x00080000) >>  6) | (($block[1] & 0x08000000) >> 15) |
+            (($block[0] & 0x00000008) <<  8) | (($block[0] & 0x00000800) >>  1) |
+            (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
+            (($block[1] & 0x00000200) >>  3) | (($block[0] & 0x00000200) >>  7) |
+            (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
+            (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
+            ($msb[1] << 28) | ($msb[0] << 24)
+        );
+
+        for ($i = 0; $i < 16; $i++) {
+            // start of "the Feistel (F) function"
+            $key  = ((($block[1] >> 27) & 0x1F)
+                    | (($block[1] & 1) << 5)) ^ $keys[$i][0];
+            $temp = ((static::$sbox[0][$key]) << 28);
+            $key  = (($block[1] & 0x1F800000) >> 23) ^ $keys[$i][1];
+            $temp |= ((static::$sbox[1][$key]) << 24);
+            $key = (($block[1] & 0x01F80000) >> 19) ^ $keys[$i][2];
+            $temp |= ((static::$sbox[2][$key]) << 20);
+            $key = (($block[1] & 0x001F8000) >> 15) ^ $keys[$i][3];
+            $temp |= ((static::$sbox[3][$key]) << 16);
+            $key = (($block[1] & 0x0001F800) >> 11) ^ $keys[$i][4];
+            $temp |= ((static::$sbox[4][$key]) << 12);
+            $key = (($block[1] & 0x00001F80) >>  7) ^ $keys[$i][5];
+            $temp |= ((static::$sbox[5][$key]) <<  8);
+            $key = (($block[1] & 0x000001F8) >>  3) ^ $keys[$i][6];
+            $temp |= ((static::$sbox[6][$key]) <<  4);
+            $key = ((($block[1] & 0x1F) << 1)
+                    | (($block[1] >> 31) & 1)) ^ $keys[$i][7];
+            $temp |= ( static::$sbox[7][$key]);
+
+            $msb   = ($temp >> 31) & 1;
+            $temp &= 0x7FFFFFFF;
+            $nwB   = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) <<  5);
+            $nwB |= (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10);
+            $nwB |= (($temp & 0x00000008) << 24) | (($temp & 0x00100000) <<  6);
+            $nwB |= (($temp & 0x00000010) << 21) | (($temp & 0x00008000) <<  9);
+            $nwB |= (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27);
+            $nwB |= (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >>  8);
+            $nwB |= (($temp & 0x00004000) <<  4) | (($temp & 0x00000002) << 16);
+            $nwB |= (($temp & 0x00442000) >>  6) | (($temp & 0x40800000) >> 15);
+            $nwB |= (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20);
+            $nwB |= (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) <<  3);
+            $nwB |= (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >>  7);
+            $nwB |= (($temp & 0x00200000) >> 19) | ($msb << 23);
+            // end of "the Feistel (F) function" - $newBlock is F's output
+
+            $temp     = $block[1];
+            $block[1] = $block[0] ^ $nwB;
+            $block[0] = $temp;
+        }
+
+        $msb       = array(
+            ($block[0] >> 31) & 1,
+            ($block[1] >> 31) & 1
+        );
+        $block[0] &= 0x7FFFFFFF;
+        $block[1] &= 0x7FFFFFFF;
+
+        $block = array(
+            (($block[0] & 0x01000004) <<  7) | (($block[1] & 0x01000004) <<  6) |
+            (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
+            (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
+            (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
+            (($block[0] & 0x02000008) >>  2) | (($block[1] & 0x02000008) >>  3) |
+            (($block[0] & 0x00020000) <<  4) | (($block[1] & 0x00020000) <<  3) |
+            (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) <<  9) |
+            (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
+            (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
+            (($block[0] & 0x00040000) >>  5) | (($block[1] & 0x00040000) >>  6) |
+            (($block[0] & 0x00000400) <<  1) | ( $block[1] & 0x00000400       ) |
+            (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
+            (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
+            (($block[0] & 0x00000800) >>  8) | (($block[1] & 0x00000800) >>  9),
+            (($block[0] & 0x10000040) <<  3) | (($block[1] & 0x10000040) <<  2) |
+            (($block[0] & 0x00100000) <<  9) | (($block[1] & 0x00100000) <<  8) |
+            (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
+            (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
+            (($block[0] & 0x20000080) >>  6) | (($block[1] & 0x20000080) >>  7) |
+            ( $block[0] & 0x00200000       ) | (($block[1] & 0x00200000) >>  1) |
+            (($block[0] & 0x00002000) <<  6) | (($block[1] & 0x00002000) <<  5) |
+            (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
+            (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
+            (($block[0] & 0x00400000) >>  9) | (($block[1] & 0x00400000) >> 10) |
+            (($block[0] & 0x00004000) >>  3) | (($block[1] & 0x00004000) >>  4) |
+            (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
+            (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
+            ($msb[0] <<  7) | ($msb[1] <<  6)
+        );
+
+        return pack('NN', $block[0], $block[1]);
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Cipher/MCrypt.php b/CryptLib/Cipher/Block/Cipher/MCrypt.php
new file mode 100644 (file)
index 0000000..527a28e
--- /dev/null
@@ -0,0 +1,152 @@
+<?php
+/**
+ * The mcrypt block cipher implementation
+ *
+ * This class is used above all other implementations since it uses a core PHP
+ * library if it is available.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Cipher;
+
+/**
+ * The mcrypt block cipher implementation
+ *
+ * This class is used above all other implementations since it uses a core PHP
+ * library if it is available.
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class MCrypt extends \CryptLib\Cipher\Block\AbstractCipher {
+
+    /**
+     * @var resource The mcrypt resource for cipher operations
+     */
+    protected $mcrypt = null;
+
+    /**
+     * Get a list of supported ciphers for this class implementation
+     *
+     * @return array A list of supported ciphers
+     */
+    public static function getSupportedCiphers() {
+        // @codeCoverageIgnoreStart
+        if (!function_exists('mcrypt_list_algorithms')) {
+            return array();
+        }
+        // @codeCoverageIgnoreEnd
+        return mcrypt_list_algorithms();
+    }
+
+    /**
+     * Construct the instance for the supplied cipher name
+     *
+     * @param string $cipher The cipher to implement
+     *
+     * @return void
+     * @throws InvalidArgumentException if the cipher is not supported
+     */
+    public function __construct($cipher) {
+        parent::__construct($cipher);
+        $this->keySize   = mcrypt_get_key_size($cipher, MCRYPT_MODE_ECB);
+        $this->blockSize = mcrypt_get_block_size($cipher, MCRYPT_MODE_ECB);
+    }
+
+    /**
+     * Destroy the mcrypt module if it's open
+     *
+     * @return void
+     */
+    public function __destruct() {
+        if ($this->mcrypt) {
+            mcrypt_module_close($this->mcrypt);
+        }
+    }
+
+    /**
+     * Set the key to use for the cipher
+     *
+     * @param string $key The key to use
+     *
+     * @throws InvalidArgumentException If the key is not the correct size
+     * @return void
+     */
+    public function setKey($key) {
+        switch ($this->cipher) {
+            case 'rijndael-128':
+            case 'rijndael-192':
+            case 'rijndael-256':
+                if (!in_array(strlen($key), array(16, 20, 24, 28, 32))) {
+                    throw new \InvalidArgumentException(
+                        sprintf(
+                            'The supplied key block is in the valid sizes [%d:%s]',
+                            strlen($key),
+                            '16, 20, 24, 28, 32'
+                        )
+                    );
+                }
+                $this->keySize = strlen($key);
+            default:
+                parent::setKey($key);
+        }
+    }
+
+    /**
+     * Decrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     */
+    protected function decryptBlockData($data) {
+        return mdecrypt_generic($this->mcrypt, $data);
+    }
+
+    /**
+     * Encrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     */
+    protected function encryptBlockData($data) {
+        return mcrypt_generic($this->mcrypt, $data);
+    }
+
+    /**
+     * Initialize the cipher by preparing the key
+     *
+     * @return boolean The status of the initialization
+     * @codeCoverageIgnore
+     */
+    protected function initialize() {
+        if ($this->mcrypt) {
+            mcrypt_module_close($this->mcrypt);
+        }
+        $this->mcrypt = mcrypt_module_open($this->cipher, '', MCRYPT_MODE_ECB, '');
+        if ($this->mcrypt) {
+            $initv = str_repeat(chr(0), $this->getBlockSize());
+            return false !== mcrypt_generic_init($this->mcrypt, $this->key, $initv);
+        }
+        return false;
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Cipher/Rijndael.php b/CryptLib/Cipher/Block/Cipher/Rijndael.php
new file mode 100644 (file)
index 0000000..c451a51
--- /dev/null
@@ -0,0 +1,655 @@
+<?php
+
+/**
+ * An implementation of the Rijndael cipher, using the phpseclib implementation
+ * 
+ * This was forked from phpseclib and modified to use CryptLib conventions
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Jim Wigginton <terrafrost@php.net>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Cipher;
+
+/**
+ * An implementation of the Rijndael cipher, using the phpseclib implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Rijndael extends \CryptLib\Cipher\Block\AbstractCipher {
+
+    /**
+     * @var int The number of bytes in each block
+     */
+    protected $blockSize = 16;
+
+    /**
+     * @var array The decryption key schedule
+     */
+    protected $decryptionSchedule = array();
+
+    /**
+     * @var array The encryption key schedule
+     */
+    protected $encryptionSchedule = array();
+
+    /**
+     * @var int The number of bytes in the key
+     */
+    protected $keySize = 16;
+
+    /**
+     * @var array The shift offsets used by the cipher
+     */
+    protected $shiftOffsets = array(0, 1, 2, 3);
+
+    /**
+     * @var array The rcon static array
+     */
+    protected static $rcon = array(0,
+        0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
+        0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
+        0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
+        0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
+        0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
+        0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
+    );
+
+    /**
+     * @var array The initial t array used by the cipher
+     */
+    protected static $tValues = array(
+        0 => array(),
+        1 => array(),
+        2 => array(),
+        3 => array(
+            0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6,
+            0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56,
+            0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F,
+            0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
+            0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753,
+            0x727296E4, 0xC0C05B9B, 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C,
+            0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 0x34345C68, 0xA5A5F451,
+            0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
+            0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137,
+            0x05050F0A, 0x9A9AB52F, 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF,
+            0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 0x09091B12, 0x83839E1D,
+            0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
+            0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD,
+            0x2F2F715E, 0x84849713, 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1,
+            0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 0x6A6ABED4, 0xCBCB468D,
+            0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
+            0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A,
+            0x33335566, 0x85859411, 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE,
+            0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 0x5151F3A2, 0xA3A3FE5D,
+            0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
+            0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5,
+            0xF3F30EFD, 0xD2D26DBF, 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3,
+            0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 0xC4C45793, 0xA7A7F255,
+            0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
+            0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54,
+            0x9090AB3B, 0x8888830B, 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28,
+            0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 0xE0E03BDB, 0x32325664,
+            0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
+            0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431,
+            0xE4E437D3, 0x79798BF2, 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA,
+            0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 0x6C6CB4D8, 0x5656FAAC,
+            0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
+            0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157,
+            0xB4B4C773, 0xC6C65197, 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E,
+            0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 0x707090E0, 0x3E3E427C,
+            0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
+            0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899,
+            0x1D1D273A, 0x9E9EB927, 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322,
+            0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 0x9B9BB62D, 0x1E1E223C,
+            0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
+            0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7,
+            0x4242C684, 0x6868B8D0, 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E,
+            0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
+        )
+    );
+
+    /**
+     * @var array The initial Decryption t value array
+     */
+    protected static $dtValues = array(
+        0 => array(),
+        1 => array(),
+        2 => array(),
+        3 => array(
+            0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F,
+            0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5,
+            0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725,
+            0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
+            0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358,
+            0xE0692949, 0xC9C8448E, 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27,
+            0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 0xDF4A1863, 0x1A3182E5,
+            0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
+            0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272,
+            0x1F8F57E3, 0x55AB2A66, 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3,
+            0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 0xCF1C2B8A, 0x79B492A7,
+            0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
+            0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40,
+            0x719F065E, 0x6E1051BD, 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D,
+            0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 0x98FB2419, 0xBDE997D6,
+            0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
+            0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832,
+            0x1170AC1E, 0x5A724E6C, 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736,
+            0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 0x0A67B10C, 0x57E70F93,
+            0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
+            0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2,
+            0xB6A8B92D, 0x1EA9C814, 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3,
+            0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 0x4329768B, 0x23C6DCCB,
+            0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
+            0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC,
+            0x8652EC0D, 0xC1E3D077, 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247,
+            0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 0x494EC787, 0x38D1C1D9,
+            0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
+            0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890,
+            0x39F75E2E, 0xC3AFF582, 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF,
+            0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 0x267809CD, 0x5918F46E,
+            0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
+            0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A,
+            0xA59430C6, 0xA266C035, 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533,
+            0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 0x4DD68D76, 0xEFB04D43,
+            0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
+            0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292,
+            0x105633E9, 0xD647136D, 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB,
+            0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 0xD2DF599C, 0xF2733F55,
+            0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
+            0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC,
+            0x3C498B28, 0x0D9541FF, 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064,
+            0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
+        )
+    );
+
+    /**
+     * @var array The sboxes used for key expansion
+     */
+    protected static $sboxes = array(
+        0 => array(
+            0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
+            0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+            0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
+            0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+            0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
+            0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+            0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
+            0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+            0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
+            0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+            0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
+            0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+            0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
+            0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+            0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
+            0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+            0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
+            0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+            0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
+            0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+            0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
+            0xB0, 0x54, 0xBB, 0x16
+        ),
+        1 => array(),
+        2 => array(),
+        3 => array(),
+    );
+
+    /**
+     * @var array The inverse sboxes used for decryption 
+     */
+    protected static $invSBoxes = array(
+        0 => array(
+            0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
+            0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+            0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
+            0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+            0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
+            0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+            0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
+            0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+            0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
+            0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+            0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
+            0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+            0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
+            0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+            0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
+            0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+            0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
+            0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+            0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
+            0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+            0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
+            0x55, 0x21, 0x0C, 0x7D
+        ),
+        1 => array(),
+        2 => array(),
+        3 => array(),
+    );
+
+    /**
+     * Get a list of supported ciphers for this class implementation
+     *
+     * @return array A list of supported ciphers
+     */
+    public static function getSupportedCiphers() {
+        return array(
+            'rijndael-128',
+            'rijndael-160',
+            'rijndael-192',
+            'rijndael-224',
+            'rijndael-256',
+        );
+    }
+
+    /**
+     * Initialize the tValues,dtValues,sboxes and inverseSBoxes arrays 
+     * by calculating.  Since this only needs to be done once, it's 
+     * a static method
+     * 
+     * @return void
+     */
+    protected static function init() {
+        if (empty(static::$tValues[0])) {
+            $t_3 = static::$tValues[3];
+            $dt3 = static::$dtValues[3];
+            for ($i = 0; $i < 256; $i++) {
+                static::$tValues[2][$i << 8]  = (($t_3[$i] << 8) & 0xFFFFFF00)
+                    | (($t_3[$i] >> 24) & 0x000000FF);
+                static::$tValues[1][$i << 16] = (($t_3[$i] << 16) & 0xFFFF0000)
+                    | (($t_3[$i] >> 16) & 0x0000FFFF);
+                static::$tValues[0][$i << 24] = (($t_3[$i] << 24) & 0xFF000000)
+                    | (($t_3[$i] >> 8) & 0x00FFFFFF);
+
+                static::$dtValues[2][$i << 8]  = (($dt3[$i] << 8) & 0xFFFFFF00)
+                    | (($dt3[$i] >> 24) & 0x000000FF);
+                static::$dtValues[1][$i << 16] = (($dt3[$i] << 16) & 0xFFFF0000)
+                    | (($dt3[$i] >> 16) & 0x0000FFFF);
+                static::$dtValues[0][$i << 24] = (($dt3[$i] << 24) & 0xFF000000)
+                    | (($dt3[$i] >> 8) & 0x00FFFFFF);
+
+                static::$sboxes[1][$i << 8]     = static::$sboxes[0][$i] << 8;
+                static::$sboxes[2][$i << 16]    = static::$sboxes[0][$i] << 16;
+                static::$sboxes[3][$i << 24]    = static::$sboxes[0][$i] << 24;
+                static::$invSBoxes[1][$i << 8]  = static::$invSBoxes[0][$i] << 8;
+                static::$invSBoxes[2][$i << 16] = static::$invSBoxes[0][$i] << 16;
+                static::$invSBoxes[3][$i << 24] = static::$invSBoxes[0][$i] << 24;
+            }
+        }
+    }
+
+    /**
+     * Construct the instance for the supplied cipher name
+     *
+     * @param string $cipher The cipher to implement
+     *
+     * @return void
+     * @throws InvalidArgumentException if the cipher is not supported
+     */
+    public function __construct($cipher) {
+        parent::__construct($cipher);
+        list (, $bits) = explode('-', $cipher, 2);
+        $this->setBlockSize($bits);
+        $this->setKeySize($bits);
+        static::init();
+    }
+
+    /**
+     * Set the key to use for the cipher
+     *
+     * @param string $key The key to use
+     * 
+     * @throws InvalidArgumentException If the key is not the correct size
+     * @return void
+     */
+    public function setKey($key) {
+        $length = strlen($key);
+        if ($length != $this->keySize) {
+            $this->setKeySize($length << 3);
+            if ($length != $this->keySize) {
+                throw new \InvalidArgumentException(
+                    'The key is not of a supported length'
+                );
+            }
+        }
+        $this->key         = $key;
+        $this->initialized = $this->initialize();
+    }
+
+    /**
+     * Decrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     */
+    protected function decryptBlockData($data) {
+        $schedule = $this->decryptionSchedule;
+        return $this->decryptBlockPart($data, $schedule);
+    }
+
+    /**
+     * Encrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     */
+    protected function encryptBlockData($data) {
+        $schedule = $this->encryptionSchedule;
+        return $this->encryptBlockPart($data, $schedule);
+    }
+
+    /**
+     * Initialize the cipher by preparing the key
+     *
+     * @return boolean The status of the initialization
+     */
+    protected function initialize() {
+        $this->encryptionSchedule = $this->getEncryptionSchedule($this->key);
+        $this->decryptionSchedule = $this->getDecryptionSchedule($this->key);
+        return true;
+    }
+
+    /**
+     * Encrypt a piece of the block (a single block sized chunk)
+     *
+     * @param string $part     The block part to encrypt
+     * @param array  $schedule The key schedule to use for encryption
+     * 
+     * @return string The encrypted string
+     */
+    protected function encryptBlockPart($part, array $schedule) {
+        $words = unpack('N*words', $part);
+        $state = array();
+        $ictr  = 0;
+        foreach ($words as $word) {
+            $state[] = $word ^ $schedule[0][$ictr++];
+        }
+        $nBlocks = $this->blockSize >> 2;
+        $nKeys   = $this->keySize >> 2;
+        $nRounds = max($nBlocks, $nKeys) + 6;
+        $temp    = array();
+        for ($round = 1; $round < $nRounds; $round++) {
+            $ictr = $this->shiftOffsets[0];
+            $jctr = $this->shiftOffsets[1];
+            $kctr = $this->shiftOffsets[2];
+            $lctr = $this->shiftOffsets[3];
+            while ($ictr < $nBlocks) {
+                $temp[$ictr] = static::$tValues[0][$state[$ictr] & 0xFF000000]
+                    ^ static::$tValues[1][$state[$jctr] & 0x00FF0000]
+                    ^ static::$tValues[2][$state[$kctr] & 0x0000FF00]
+                    ^ static::$tValues[3][$state[$lctr] & 0x000000FF]
+                    ^ $schedule[$round][$ictr];
+                $ictr++;
+                $jctr = ($jctr + 1) % $nBlocks;
+                $kctr = ($kctr + 1) % $nBlocks;
+                $lctr = ($lctr + 1) % $nBlocks;
+            }
+            for ($i = 0; $i < $nBlocks; $i++) {
+                $state[$i] = $temp[$i];
+            }
+        }
+        for ($i = 0; $i < $nBlocks; $i++) {
+            $state[$i] = $this->subWord($state[$i]);
+        }
+        $ictr = $this->shiftOffsets[0];
+        $jctr = $this->shiftOffsets[1];
+        $kctr = $this->shiftOffsets[2];
+        $lctr = $this->shiftOffsets[3];
+        while ($ictr < $nBlocks) {
+            $temp[$ictr] = ($state[$ictr] & 0xFF000000)
+                ^ ($state[$jctr] & 0x00FF0000)
+                ^ ($state[$kctr] & 0x0000FF00)
+                ^ ($state[$lctr] & 0x000000FF)
+                ^ $schedule[$nRounds][$ictr];
+            $ictr++;
+            $jctr = ($jctr + 1) % $nBlocks;
+            $kctr = ($kctr + 1) % $nBlocks;
+            $lctr = ($lctr + 1) % $nBlocks;
+        }
+        $state = $temp;
+        array_unshift($state, 'N*');
+        return call_user_func_array('pack', $state);
+    }
+
+    /**
+     * Decrypt a piece of the block (a single block sized chunk)
+     *
+     * @param string $part     The block part to decrypt
+     * @param array  $schedule The key schedule to use for decryption
+     * 
+     * @return string The decrypted string
+     */
+    protected function decryptBlockPart($part, $schedule) {
+        $state   = array();
+        $words   = unpack('N*word', $part);
+        $inc     = 0;
+        $nBlocks = $this->blockSize >> 2;
+        $nKeys   = $this->keySize >> 2;
+        $nRounds = max($nBlocks, $nKeys) + 6;
+        foreach ($words as $word) {
+            $state[] = $word ^ $schedule[$nRounds][$inc++];
+        }
+        $temp = array();
+        for ($round = $nRounds - 1; $round > 0; $round--) {
+            $ictr = $this->shiftOffsets[0];
+            $jctr = $nBlocks - $this->shiftOffsets[1];
+            $kctr = $nBlocks - $this->shiftOffsets[2];
+            $lctr = $nBlocks - $this->shiftOffsets[3];
+
+            while ($ictr < $nBlocks) {
+                $temp[$ictr] = static::$dtValues[0][$state[$ictr] & 0xFF000000]
+                    ^ static::$dtValues[1][$state[$jctr] & 0x00FF0000]
+                    ^ static::$dtValues[2][$state[$kctr] & 0x0000FF00]
+                    ^ static::$dtValues[3][$state[$lctr] & 0x000000FF]
+                    ^ $schedule[$round][$ictr];
+                $ictr++;
+                $jctr = ($jctr + 1) % $nBlocks;
+                $kctr = ($kctr + 1) % $nBlocks;
+                $lctr = ($lctr + 1) % $nBlocks;
+            }
+            for ($i = 0; $i < $nBlocks; $i++) {
+                $state[$i] = $temp[$i];
+            }
+        }
+        $ictr = $this->shiftOffsets[0];
+        $jctr = $nBlocks - $this->shiftOffsets[1];
+        $kctr = $nBlocks - $this->shiftOffsets[2];
+        $lctr = $nBlocks - $this->shiftOffsets[3];
+        $temp = array();
+        while ($ictr < $nBlocks) {
+            $temp[$ictr] = $schedule[0][$ictr]
+                ^ $this->invSubWord(
+                    ($state[$ictr] & 0xFF000000)
+                    | ($state[$jctr] & 0x00FF0000)
+                    | ($state[$kctr] & 0x0000FF00)
+                    | ($state[$lctr] & 0x000000FF)
+            );
+            $ictr++;
+            $jctr = ($jctr + 1) % $nBlocks;
+            $kctr = ($kctr + 1) % $nBlocks;
+            $lctr = ($lctr + 1) % $nBlocks;
+        }
+        $state = $temp;
+        array_unshift($state, 'N*');
+        return call_user_func_array('pack', $state);
+    }
+
+    /**
+     * Set the block size to use for the cipher
+     * 
+     * @param int $num The number of bits in the block size
+     * 
+     * @return void
+     */
+    protected function setBlockSize($num) {
+        $num >>= 5;
+        $num             = max(min($num, 8), 4);
+        $this->blockSize = $num << 2;
+    }
+
+    /**
+     * Set the key size to use for the cipher
+     *
+     * @param int $num The number of bits in the key size
+     * 
+     * @return void
+     */
+    protected function setKeySize($num) {
+        $num >>= 5;
+        $num           = max(min($num, 8), 4);
+        $this->keySize = $num << 2;
+    }
+
+    /**
+     * Setup the cipher by determining the shift offsets, the key size and 
+     * precomputing part of the key schedule
+     *
+     * @param string $key The key to setup the cipher for
+     * 
+     * @return array The precomputed schedule part
+     */
+    protected function setup($key) {
+        $this->setShiftOffsets();
+        $nBlocks = $this->blockSize >> 2;
+        $nKeys   = $this->keySize >> 2;
+        $nRounds = max($nBlocks, $nKeys) + 6;
+        $words   = array_values(unpack('N*words', $key));
+        $length  = $nBlocks * ($nRounds + 1);
+        for ($i = $nKeys; $i < $length; $i++) {
+            $temp = $words[$i - 1];
+            if ($i % $nKeys == 0) {
+                $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF);
+                $temp = $this->subWord($temp) ^ static::$rcon[$i / $nKeys];
+            } elseif ($nKeys > 6 && ($i % $nKeys == 4)) {
+                $temp = $this->subWord($temp);
+            }
+            $words[$i] = $words[$i - $nKeys] ^ $temp;
+        }
+        return $words;
+    }
+
+    /**
+     * Convert the kye into an encryption schedule
+     *
+     * @param string $key The key to use
+     * 
+     * @return array The generated key schedule
+     */
+    protected function getEncryptionSchedule($key) {
+        $words    = $this->setup($key);
+        $nBlocks  = $this->blockSize >> 2;
+        $length   = $nBlocks * (max($nBlocks, $this->keySize >> 2) + 7);
+        $schedule = array();
+        for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
+            if ($col == $nBlocks) {
+                $col = 0;
+                $row++;
+            }
+            if (!isset($schedule[$row])) {
+                $schedule[$row] = array();
+            }
+            $schedule[$row][$col] = $words[$i];
+        }
+        return $schedule;
+    }
+
+    /**
+     * Convert the kye into an decryption schedule
+     *
+     * @param string $key The key to use
+     * 
+     * @return array The generated key schedule
+     */
+    protected function getDecryptionSchedule($key) {
+        $words      = $this->getEncryptionSchedule($key);
+        $schedule   = array();
+        $length     = count($words) - 1;
+        $schedule[] = $words[0];
+        $nBlocks    = $this->blockSize >> 2;
+        for ($i = 1; $i < $length; $i++) {
+            $jctr = 0;
+            $temp = array();
+            while ($jctr < $nBlocks) {
+                $dwblock     = $this->subWord($words[$i][$jctr]);
+                $temp[$jctr] = static::$dtValues[0][$dwblock & 0xFF000000]
+                    ^ static::$dtValues[1][$dwblock & 0x00FF0000]
+                    ^ static::$dtValues[2][$dwblock & 0x0000FF00]
+                    ^ static::$dtValues[3][$dwblock & 0x000000FF];
+                $jctr++;
+            }
+            $schedule[$i] = $temp;
+        }
+        $schedule[] = $words[$length];
+        return $schedule;
+    }
+
+    /**
+     * Compute the word by merging it with the sboxes
+     *
+     * @param string $word
+     * 
+     * @return string The computed word
+     */
+    protected function subWord($word) {
+        return static::$sboxes[0][$word & 0x000000FF]
+            | static::$sboxes[1][$word & 0x0000FF00]
+            | static::$sboxes[2][$word & 0x00FF0000]
+            | static::$sboxes[3][$word & 0xFF000000];
+    }
+
+    /**
+     * Compute the word by merging it with the inverse sboxes
+     *
+     * @param string $word
+     * 
+     * @return string The computed word
+     */
+    protected function invSubWord($word) {
+        return static::$invSBoxes[0][$word & 0x000000FF]
+            | static::$invSBoxes[1][$word & 0x0000FF00]
+            | static::$invSBoxes[2][$word & 0x00FF0000]
+            | static::$invSBoxes[3][$word & 0xFF000000];
+    }
+
+    /**
+     * Setup the shift offsets to use for the cipher
+     * 
+     * @return void
+     */
+    protected function setShiftOffsets() {
+        switch ($this->blockSize >> 2) {
+            case 4:
+            case 5:
+            case 6:
+                $this->shiftOffsets = array(0, 1, 2, 3);
+                break;
+            case 7:
+                $this->shiftOffsets = array(0, 1, 2, 4);
+                break;
+            case 8:
+                $this->shiftOffsets = array(0, 1, 3, 4);
+        }
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Cipher/TripleDES.php b/CryptLib/Cipher/Block/Cipher/TripleDES.php
new file mode 100644 (file)
index 0000000..48ac826
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+/**
+ * An implementation of the TripleDES cipher
+ * 
+ * This was forked from phpseclib and modified to use CryptLib conventions
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @author     Jim Wigginton <terrafrost@php.net>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Cipher;
+
+/**
+ * An implementation of the TripleDES Cipher
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class TripleDES extends DES {
+
+    /**
+     * @var int The key size for the cipher
+     */
+    protected $keySize = 24;
+
+    /**
+     * Get a list of supported ciphers for this class implementation
+     *
+     * @return array A list of supported ciphers
+     */
+    public static function getSupportedCiphers() {
+        return array('tripledes');
+    }
+
+    /**
+     * Set the key to use for the cipher
+     *
+     * @param string $key The key to use
+     * 
+     * @throws InvalidArgumentException If the key is not the correct size
+     * @return void
+     */
+    public function setKey($key) {
+        $len = strlen($key);
+        if ($len == 16) {
+            $key .= substr($key, 0, 8);
+        } elseif ($len != 24) {
+            throw new \InvalidArgumentException(
+                'The supplied key block is not the correct size'
+            );
+        }
+        $this->key         = $key;
+        $this->initialized = true;
+    }
+
+    /**
+     * Decrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The result decrypted data
+     */
+    protected function decryptBlockData($data) {
+        $key       = $this->key;
+        $this->key = substr($key, 16, 8);
+        $this->initialize();
+        $data      = parent::decryptBlockData($data);
+        $this->key = substr($key, 8, 8);
+        $this->initialize();
+        $data      = parent::encryptBlockData($data);
+        $this->key = substr($key, 0, 8);
+        $this->initialize();
+        $data      = parent::decryptBlockData($data);
+        $this->key = $key;
+        return $data;
+    }
+
+    /**
+     * Encrypt a block of data using the supplied string key
+     *
+     * Note that the supplied data should be the same size as the block size of
+     * the cipher being used.
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The result encrypted data
+     */
+    protected function encryptBlockData($data) {
+        $key       = $this->key;
+        $this->key = substr($key, 0, 8);
+        $this->initialize();
+        $data      = parent::encryptBlockData($data);
+        $this->key = substr($key, 8, 8);
+        $this->initialize();
+        $data      = parent::decryptBlockData($data);
+        $this->key = substr($key, 16, 8);
+        $this->initialize();
+        $data      = parent::encryptBlockData($data);
+        $this->key = $key;
+        return $data;
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode.php b/CryptLib/Cipher/Block/Mode.php
new file mode 100644 (file)
index 0000000..4849499
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * The interface that all block cipher modes must implement
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block;
+
+/**
+ * The interface that all block cipher modes must implement
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface Mode {
+
+    /**
+     * Build the instance of the cipher mode
+     *
+     * @param Cipher $cipher  The cipher to use for encryption/decryption
+     * @param string $initv   The initialization vector (empty if not needed)
+     * @param array  $options An array of mode-specific options
+     */
+    public function __construct(
+        \CryptLib\Cipher\Block\Cipher $cipher,
+        $initv,
+        array $options = array()
+    );
+
+    /**
+     * Decrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    public function decrypt($data);
+
+    /**
+     * Encrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    public function encrypt($data);
+
+    /**
+     * Finish the mode and append any additional data necessary
+     *
+     * @return string Any additional data
+     */
+    public function finish();
+
+    /**
+     * Get the name of the current mode implementation
+     *
+     * @return string The current mode name
+     */
+    public function getMode();
+
+    /**
+     * Reset the mode to start over (destroying any intermediate state)
+     *
+     * @return void
+     */
+    public function reset();
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/CBC.php b/CryptLib/Cipher/Block/Mode/CBC.php
new file mode 100644 (file)
index 0000000..a8d3a62
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * The CBC (Cipher Block Chaining) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+/**
+ * The CBC (Cipher Block Chaining) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+
+class CBC extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * Decrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        $stub        = $this->cipher->decryptBlock($data);
+        $result      = $stub ^ $this->state;
+        $this->state = $data;
+        return $result;
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        $stub        = $this->cipher->encryptBlock($data ^ $this->state);
+        $this->state = $stub;
+        return $stub;
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/CCM.php b/CryptLib/Cipher/Block/Mode/CCM.php
new file mode 100644 (file)
index 0000000..5bffa7e
--- /dev/null
@@ -0,0 +1,374 @@
+<?php
+/**
+ * The CCM (Counter CBC-MAC) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ * @see        http://tools.ietf.org/html/rfc3610
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+/**
+ * The CCM (Counter CBC-MAC) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @see        http://tools.ietf.org/html/rfc3610
+ */
+class CCM extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * Indicates which mode the cipher mode is in (encryption/decryption)
+     */
+    const MODE_DECRYPT = 1;
+
+    /**
+     * Indicates which mode the cipher mode is in (encryption/decryption)
+     */
+    const MODE_ENCRYPT = 2;
+
+    /**
+     * @var int The number of octets in the Authentication field
+     */
+    protected $authFieldSize = 8;
+
+    /**
+     * @var string The data buffer for this encryption instance
+     */
+    protected $data = '';
+
+    /**
+     * @var int The number of octets in the length field
+     */
+    protected $lSize = 4;
+
+    /**
+     * @var string The mode name for the current instance
+     */
+    protected $mode = 'ccm';
+
+    /**
+     * @var int The current encryption mode (enc/dec)
+     */
+    protected $encryptionMode = 0;
+
+    /**
+     * @var array Mode specific options
+     */
+    protected $options = array(
+        'adata' => '',
+        'lSize' => 4,
+        'aSize' => 8,
+    );
+
+    /**
+     * @var string The initialization vector to use for this instance
+     */
+    protected $usedIV = '';
+
+    /**
+     * Build the instance of the cipher mode
+     *
+     * @param Cipher $cipher  The cipher to use for encryption/decryption
+     * @param string $initv   The initialization vector (empty if not needed)
+     * @param array  $options An array of mode-specific options
+     */
+    public function __construct(
+        \CryptLib\Cipher\Block\Cipher $cipher,
+        $initv,
+        array $options = array()
+    ) {
+        $this->options = $options + $this->options;
+        $this->cipher  = $cipher;
+        $this->initv   = $initv;
+        $this->adata   = $this->options['adata'];
+        $this->setLSize($this->options['lSize']);
+        $this->setAuthFieldSize($this->options['aSize']);
+        $this->reset();
+    }
+
+    /**
+     * Finish the mode and append any additional data necessary
+     *
+     * @return string Any additional data
+     */
+    public function finish() {
+        $mask = (static::MODE_DECRYPT | static::MODE_ENCRYPT);
+        if (!($this->encryptionMode ^ $mask)) {
+            throw new \LogicException('Cannot encrypt and decrypt in same state');
+        }
+        if ($this->encryptionMode & static::MODE_DECRYPT) {
+            return $this->decryptBlockFinal();
+        } else {
+            return $this->encryptBlockFinal();
+        }
+    }
+
+    /**
+     * Set the auth field size to a different value.
+     *
+     * Valid values: 4, 6, 8, 10, 12, 14, 16
+     *
+     * Note that increasing this size will make it harder for an attacker to
+     * modify the message payload
+     *
+     * @param int $new The new size of auth field to append
+     *
+     * @return void
+     * @throws InvalidArgumentException If the number is outside of the range
+     */
+    public function setAuthFieldSize($new) {
+        if (!in_array($new, array(4, 6, 8, 10, 12, 14, 16))) {
+            throw new \InvalidArgumentException(
+                'The Auth Field must be one of: 4, 6, 8, 10, 12, 14, 16'
+            );
+        }
+        $this->authFieldSize = (int) $new;
+        $this->reset();
+    }
+
+    /**
+     * Set the size of the length field.  This is a tradeoff between the maximum
+     * message size and the size of the initialization vector
+     *
+     * Valid values are 2, 3, 4, 5, 6, 7, 8
+     *
+     * @param int $new The new LSize to use
+     *
+     * @return void
+     * @throws InvalidArgumentException If the number is outside of the range
+     */
+    public function setLSize($new) {
+        if ($new < 2 || $new > 8) {
+            throw new \InvalidArgumentException(
+                'The LSize must be between 2 and 8 inclusive'
+            );
+        }
+        $this->lSize = (int) $new;
+        $this->reset();
+    }
+
+    /**
+     * Reset the mode to start over (destroying any intermediate state)
+     *
+     * @return void
+     */
+    public function reset() {
+        $this->usedIV         = $this->extractInitv(
+            $this->initv,
+            $this->cipher->getBlockSize()
+        );
+        $this->encryptionMode = 0;
+        $this->data           = '';
+    }
+
+    /**
+     * Decrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        $this->data .= $data;
+        $this->encryptionMode |= static::MODE_DECRYPT;
+    }
+
+    /**
+     * Perform the decryption of the block data
+     *
+     * @return string The final data
+     */
+    protected function decryptBlockFinal() {
+        $message    = substr($this->data, 0, -1 * $this->authFieldSize);
+        $uValue     = substr($this->data, -1 * $this->authFieldSize);
+        $data       = $this->encryptMessage($message, $uValue);
+        $computedT  = substr($data, -1 * $this->authFieldSize);
+        $data       = substr($data, 0, -1 * $this->authFieldSize);
+        $authFieldT = $this->computeAuthField($data);
+        if ($authFieldT != $computedT) {
+            return false;
+        }
+        return rtrim($data, chr(0));
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        $this->data .= $data;
+        $this->encryptionMode |= static::MODE_ENCRYPT;
+    }
+
+    /**
+     * Perform the encryption of the block data
+     *
+     * @return string The final data
+     */
+    protected function encryptBlockFinal() {
+        $authFieldT = $this->computeAuthField($this->data);
+        $data       = $this->encryptMessage($this->data, $authFieldT);
+        return $data;
+    }
+
+    /**
+     * Compute the authentication field
+     *
+     * @param string $data   The data to compute with
+     *
+     * @return string The computed MAC Authentication Code
+     */
+    protected function computeAuthField($data) {
+        $blockSize = $this->cipher->getBlockSize();
+        $flags     = pack(
+            'C',
+            64 * (empty($this->adata) ? 0 : 1)
+                + 8 * (($this->authFieldSize - 2) / 2)
+                + ($this->lSize - 1)
+        );
+        $blocks    = array(
+            $flags . $this->usedIV . pack($this->getLPackString(), strlen($data))
+        );
+        if (strlen($data) % $blockSize != 0) {
+            $data .= str_repeat(chr(0), $blockSize - (strlen($data) % $blockSize));
+        }
+
+        $blocks = array_merge(
+            $blocks,
+            $this->processAData($this->adata, $blockSize)
+        );
+        if (!empty($data)) {
+            $blocks = array_merge($blocks, str_split($data, $blockSize));
+        }
+        $crypted = array(
+            1 => $this->cipher->encryptBlock($blocks[0])
+        );
+
+        $blockLen = count($blocks);
+        for ($i = 1; $i < $blockLen; $i++) {
+            $crypted[$i + 1] = $this->cipher->encryptBlock(
+                $crypted[$i] ^ $blocks[$i]
+            );
+        }
+        return substr(end($crypted), 0, $this->authFieldSize);
+    }
+
+    /**
+     * Encrypt the data using the supplied method
+     *
+     * @param string $data      The data to encrypt
+     * @param string $authValue The auth value field
+     *
+     * @return string The encrypted data with authfield payload
+     */
+    protected function encryptMessage($data, $authValue) {
+        $blockSize = $this->cipher->getBlockSize();
+        $flags     = pack('C', ($this->lSize - 1));
+        $blocks    = str_split($data, $blockSize);
+        $sblocks   = array();
+        $blockLen  = count($blocks);
+        for ($i = 0; $i <= $blockLen; $i++) {
+            $sblocks[] = $this->cipher->encryptBlock(
+                $flags . $this->usedIV . pack($this->getLPackString(), $i)
+            );
+        }
+        $encrypted = '';
+        foreach ($blocks as $key => $value) {
+            if (strlen($value) < $blockSize) {
+                $sblocks[$key + 1] = substr($sblocks[$key + 1], 0, strlen($value));
+            }
+            $encrypted .= $sblocks[$key + 1] ^ $value;
+        }
+        $sValue = substr($sblocks[0], 0, $this->authFieldSize);
+        $uValue = $authValue ^ $sValue;
+        return $encrypted . $uValue;
+    }
+
+    /**
+     * Enforce the data block is the correct size for the cipher
+     *
+     * @param string $data The data to check
+     *
+     * @return void
+     * @throws InvalidArgumentException if the block size is not correct
+     */
+    protected function enforceBlockSize($data) {
+        return true;
+    }
+
+    /**
+     * Extract the nonce from the initialization vector
+     *
+     * @param string $initv     The initialization Vector to trim
+     * @param int    $blockSize The size of the final nonce
+     *
+     * @return string The sized nonce
+     * @throws InvalidArgumentException if the IV is too short
+     */
+    protected function extractInitv($initv, $blockSize) {
+        $initSize = $blockSize - 1 - $this->lSize;
+        if (strlen($initv) < $initSize) {
+            throw new \InvalidArgumentException(sprintf(
+                'Supplied Initialization Vector is too short, should be %d bytes',
+                $initSize
+            ));
+        }
+        return substr($initv, 0, $initSize);
+    }
+
+    /**
+     * Get a packing string related to the instance lSize variable
+     *
+     * @return string The pack() string to use to pack the length variables
+     * @see pack()
+     */
+    protected function getLPackString() {
+        if ($this->lSize <= 3) {
+            return str_repeat('x', $this->lSize - 2) . 'n';
+        }
+        return str_repeat('x', $this->lSize - 4) . 'N';
+    }
+
+    /**
+     * Process the Authentication data for authenticating
+     *
+     * @param string $adata     The data to authenticate with
+     * @param int    $blockSize The block size for the cipher
+     *
+     * @return array An array of strings bound by the supplied blocksize
+     */
+    protected function processAData($adata, $blockSize) {
+        if (!empty($this->adata)) {
+            if (strlen($this->adata) < ((1 << 16) - (1 << 8))) {
+                $len = pack('n', strlen($this->adata));
+            } else {
+                $len = chr(0xff) . chr(0xfe) . pack('N', strlen($this->adata));
+            }
+            $temp = $len . $this->adata;
+            if (strlen($temp) % $blockSize != 0) {
+                //Pad the string to exactly mod16
+                $temp .= str_repeat(
+                    chr(0),
+                    $blockSize - (strlen($temp) % $blockSize)
+                );
+            }
+            return str_split($temp, $blockSize);
+        }
+        return array();
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/CFB.php b/CryptLib/Cipher/Block/Mode/CFB.php
new file mode 100644 (file)
index 0000000..ddccc61
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The CFB (Cipher FeedBack) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+/**
+ * The CFB (Cipher FeedBack) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class CFB extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * Decrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        $stub        = $this->cipher->encryptBlock($this->state);
+        $rawData     = $stub ^ $data;
+        $this->state = $rawData;
+        return $rawData;
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        $stub        = $this->cipher->encryptBlock($this->state);
+        $this->state = $data;
+        return $stub ^ $data;
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/CTR.php b/CryptLib/Cipher/Block/Mode/CTR.php
new file mode 100644 (file)
index 0000000..8c17e86
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+/**
+ * The CTR (Counter) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+use CryptLib\Core\BaseConverter;
+use CryptLib\Core\BigMath;
+
+/**
+ * The CTR (Counter) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+
+class CTR extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * @var BigMath An instance of the BigMath library
+     */
+    protected $bigMath = null;
+
+    /**
+     * Build the instance of the cipher mode
+     *
+     * @param Cipher $cipher  The cipher to use for encryption/decryption
+     * @param string $initv   The initialization vector (empty if not needed)
+     * @param array  $options An array of mode-specific options
+     */
+    public function __construct(
+        \CryptLib\Cipher\Block\Cipher $cipher,
+        $initv,
+        array $options = array()
+    ) {
+        parent::__construct($cipher, $initv, $options);
+        $this->bigMath = BigMath::createFromServerConfiguration();
+    }
+
+    /**
+     * Reset the mode to start over (destroying any intermediate state)
+     *
+     * @return void
+     */
+    public function reset() {
+        $this->state = BaseConverter::ConvertFromBinary($this->initv, '0123456789');
+        $this->state = ltrim($this->state, '0');
+    }
+
+    /**
+     * Decrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        return $this->encryptBlock($data);
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        $size        = $this->cipher->getBlockSize();
+        $state       = str_pad(
+            BaseConverter::convertToBinary($this->state, '0123456789'),
+            $size,
+            chr(0),
+            STR_PAD_LEFT
+        );
+        $stub        = $this->cipher->encryptBlock($state);
+        $this->state = $this->bigMath->add($this->state, 1);
+        return $stub ^ $data;
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/ECB.php b/CryptLib/Cipher/Block/Mode/ECB.php
new file mode 100644 (file)
index 0000000..6adcb1f
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * The ECB (Electronic CodeBook) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+/**
+ * The ECB (Electronic CodeBook) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class ECB extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * Decrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        return $this->cipher->decryptBlock($data);
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        return $this->cipher->encryptBlock($data);
+    }
+
+}
diff --git a/CryptLib/Cipher/Block/Mode/NOFB.php b/CryptLib/Cipher/Block/Mode/NOFB.php
new file mode 100644 (file)
index 0000000..3ed2ac0
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * The NOFB (Nbit Output FeedBack) mode implementation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher\Block\Mode;
+
+/**
+ * The NOFB (Nbit Output FeedBack) mode implementation
+ *
+ * @category   PHPCryptLib
+ * @package    Cipher
+ * @subpackage Block
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class NOFB extends \CryptLib\Cipher\Block\AbstractMode {
+
+    /**
+     * Decrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to decrypt
+     *
+     * @return string The decrypted data
+     */
+    protected function decryptBlock($data) {
+        return $this->encryptBlock($data);
+    }
+
+    /**
+     * Encrypt the data using the supplied key, cipher and initialization vector
+     *
+     * @param string $data The data to encrypt
+     *
+     * @return string The encrypted data
+     */
+    protected function encryptBlock($data) {
+        $this->state = $this->cipher->encryptBlock($this->state);
+        return $this->state ^ $data;
+    }
+
+}
diff --git a/CryptLib/Cipher/Factory.php b/CryptLib/Cipher/Factory.php
new file mode 100644 (file)
index 0000000..ec1c512
--- /dev/null
@@ -0,0 +1,189 @@
+<?php
+/**
+ * The Cipher Factory
+ *
+ * Use this factory to instantiate ciphers and modes based upon their names. You
+ * can register new ciphers and modes by simply calling the appropriate methods.
+ *
+ * PHP version 5.3
+ *
+ * @category  PHPCryptLib
+ * @package   Cipher
+ * @author    Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright 2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Cipher;
+
+/**
+ * Some used classes, aliased appropriately
+ */
+use CryptLib\Cipher\Block\Cipher as Cipher;
+use CryptLib\Cipher\Block\Mode   as Mode;
+use CryptLib\Cipher\Block\Cipher\MCrypt;
+
+
+/**
+ * The Cipher Factory
+ *
+ * Use this factory to instantiate ciphers and modes based upon their names. You
+ * can register new ciphers and modes by simply calling the appropriate methods.
+ *
+ * @category  PHPCryptLib
+ * @package   Cipher
+ * @author    Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Factory extends \CryptLib\Core\AbstractFactory {
+
+    /**
+     * @var array A list of available cipher implementations by name of cipher
+     */
+    protected $ciphers = array();
+
+    /**
+     * @var array A list of available mode implementations by name of mode
+     */
+    protected $modes = array();
+
+    /**
+     * Instantiate the factory
+     *
+     * This automatically loads and registers the default cipher and mode
+     * implementations.
+     *
+     * @return void
+     */
+    public function __construct() {
+        $this->loadModes();
+        $this->loadCiphers();
+    }
+
+    /**
+     * Get an instance of a cipher by name
+     *
+     * Note that this will return the passed argument if it is an instance of
+     * the Block cipher interface.
+     *
+     * @param string|Block $cipher The cipher name or instance to load
+     *
+     * @return Cipher The loaded block cipher
+     * @throws RuntimeException if the cipher is not supported
+     */
+    public function getBlockCipher($cipher) {
+        if (is_object($cipher) && $cipher instanceof Cipher) {
+            return $cipher;
+        }
+        $cipher = strtolower($cipher);
+        if (in_array($cipher, MCrypt::getSupportedCiphers())) {
+            //Use the built in MCrypt library if it's available
+            return new MCrypt($cipher);
+        } elseif (isset($this->ciphers[$cipher])) {
+            $class = $this->ciphers[$cipher];
+            return new $class($cipher);
+        }
+        $message = sprintf('Unsupported Cipher %s', $cipher);
+        throw new \RuntimeException($message);
+    }
+
+    /**
+     * Get an instance of a mode by name
+     *
+     * Note that this will return the passed argument if it is an instance of
+     * the Mode interface.
+     *
+     * @param string|Mode $mode The mode name or instance to load
+     *
+     * @return Mode The loaded mode instance
+     * @throws RuntimeException if the mode is not supported
+     */
+    public function getMode(
+        $mode,
+        \CryptLib\Cipher\Block\Cipher $cipher,
+        $initv,
+        array $options = array()
+    ) {
+        if (is_object($mode) && $mode instanceof Mode) {
+            return $mode;
+        }
+        $mode = strtolower($mode);
+        if (isset($this->modes[$mode])) {
+            $class = $this->modes[$mode];
+            return new $class($cipher, $initv, $options);
+        }
+        $message = sprintf('Unsupported Mode %s', $mode);
+        throw new \RuntimeException($message);
+    }
+
+    /**
+     * Register a new cipher implementation class for this factory
+     *
+     * This will iterate over each supported cipher for the class and load the
+     * cipher into the list of supported ciphers
+     *
+     * @param string $name  The name of the cipher (ignored)
+     * @param string $class The full class name of the cipher implementation
+     *
+     * @return Factory $this The current factory instance
+     * @throws InvalidArgumentException If the class is not a block cipher
+     */
+    public function registerCipher($name, $class) {
+        $refl      = new \ReflectionClass($class);
+        $interface = '\\'. __NAMESPACE__ . '\\Block\\Cipher';
+        if (!$refl->implementsInterface($interface)) {
+            $message = sprintf('Class must implement %s', $interface);
+            throw new \InvalidArgumentException($message);
+        }
+        foreach ($class::getSupportedCiphers() as $cipher){
+            $this->ciphers[$cipher] = $class;
+        }
+        return $this;
+    }
+
+    /**
+     * Register a new mode implementation class for this factory
+     *
+     * @param string $name  The name of the mode (ignored)
+     * @param string $class The full class name of the mode implementation
+     *
+     * @return Factory $this The current factory instance
+     * @throws InvalidArgumentException If the class is not a valid mode
+     */
+    public function registerMode($name, $class) {
+        $refl      = new \ReflectionClass($class);
+        $interface = '\\'. __NAMESPACE__ . '\\Block\\Mode';
+        if (!$refl->implementsInterface($interface)) {
+            throw new \InvalidArgumentException('Class must implement Mode');
+        }
+        $this->modes[strtolower($name)] = $class;
+        return $this;
+    }
+
+    /**
+     * Load all core cipher implementations
+     *
+     * @return void
+     */
+    protected function loadCiphers() {
+        $this->loadFiles(
+            __DIR__ . '/Block/Cipher',
+            __NAMESPACE__ . '\\Block\\Cipher\\',
+            array($this, 'registerCipher')
+        );
+    }
+
+    /**
+     * Load all core mode implementations
+     *
+     * @return void
+     */
+    protected function loadModes() {
+        $this->loadFiles(
+            __DIR__ . '/Block/Mode',
+            __NAMESPACE__ . '\\Block\\Mode\\',
+            array($this, 'registerMode')
+        );
+    }
+
+}
diff --git a/CryptLib/Core/AbstractFactory.php b/CryptLib/Core/AbstractFactory.php
new file mode 100644 (file)
index 0000000..eb7fc48
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+/**
+ * The base abstract factory used by all CryptLib factories
+ *
+ * PHP version 5.3
+ *
+ * @category  PHPCryptLib
+ * @package   Core
+ * @author    Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright 2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version   Build @@version@@
+ */
+
+namespace CryptLib\Core;
+
+/**
+ * The base abstract factory used by all CryptLib factories
+ *
+ * @category PHPCryptLib
+ * @package  Core
+ * @author   Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class AbstractFactory {
+
+    /**
+     * Register a type with the factory by name
+     *
+     * This is an internal method to check if a provided class name implements
+     * an interface, and if it does to append that class to an internal array
+     * by name.
+     *
+     * @param string  $type        The name of the variable to store the class
+     * @param string  $implements  The interface to validate against
+     * @param string  $name        The name of this particular class
+     * @param string  $class       The fully qualified class name
+     * @param boolean $instantiate Should the class be stored instantiated
+     *
+     * @return void
+     * @throws InvalidArgumentException If class does not implement interface
+     */
+    protected function registerType(
+        $type,
+        $implements,
+        $name,
+        $class,
+        $instantiate = false
+    ) {
+        $name = strtolower($name);
+        $refl = new \ReflectionClass($class);
+        if (!$refl->implementsInterface($implements)) {
+            $message = sprintf('Class must implement %s', $implements);
+            throw new \InvalidArgumentException($message);
+        }
+        if ($instantiate) {
+            $class = new $class;
+        }
+
+        $this->{$type}[$name] = $class;
+    }
+
+    /**
+     * Load a set of classes from a directory into the factory
+     *
+     * @param string $directory The directory to search for classes in
+     * @param string $namespace The namespace prefix for any found classes
+     * @param string $callback  The callback with which to register the class
+     *
+     * @return void
+     */
+    protected function loadFiles($directory, $namespace, $callback) {
+        foreach (new \DirectoryIterator($directory) as $file) {
+            $filename = $file->getBasename();
+            if ($file->isFile() && substr($filename, -4) == '.php') {
+                $name  = substr($filename, 0, -4);
+                $class = $namespace . $name;
+                call_user_func($callback, $name, $class);
+            }
+        }
+    }
+
+}
diff --git a/CryptLib/Core/AutoLoader.php b/CryptLib/Core/AutoLoader.php
new file mode 100644 (file)
index 0000000..ddd769e
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+/**
+ * An implementation of the PSR-0 Autoloader.  This can be replaced at will with
+ * other implementations if necessary.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Core;
+
+/**
+ * An implementation of the PSR-0 Autoloader.  This can be replaced at will with
+ * other implementations if necessary.
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class AutoLoader {
+
+    /**
+     * @var string The namespace prefix for this instance.
+     */
+    protected $namespace = '';
+
+    /**
+     * @var string The filesystem prefix to use for this instance
+     */
+    protected $path = '';
+
+    /**
+     * Build the instance of the autoloader
+     *
+     * @param string $namespace The prefixed namespace this instance will load
+     * @param string $path      The filesystem path to the root of the namespace
+     *
+     * @return void
+     */
+    public function __construct($namespace, $path) {
+        $this->namespace = ltrim($namespace, '\\');
+        $this->path      = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
+    }
+
+    /**
+     * Try to load a class
+     *
+     * @param string $class The class name to load
+     *
+     * @return boolean If the loading was successful
+     */
+    public function load($class) {
+        $class = ltrim($class, '\\');
+        if (strpos($class, $this->namespace) === 0) {
+            $nsparts   = explode('\\', $class);
+            $class     = array_pop($nsparts);
+            $nsparts[] = '';
+            $path      = $this->path . implode(DIRECTORY_SEPARATOR, $nsparts);
+            $path     .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+            if (file_exists($path)) {
+                require $path;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Register the autoloader to PHP
+     *
+     * @return boolean The status of the registration
+     */
+    public function register() {
+        return spl_autoload_register(array($this, 'load'));
+    }
+
+    /**
+     * Unregister the autoloader to PHP
+     *
+     * @return boolean The status of the unregistration
+     */
+    public function unregister() {
+        return spl_autoload_unregister(array($this, 'load'));
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/BaseConverter.php b/CryptLib/Core/BaseConverter.php
new file mode 100644 (file)
index 0000000..9c086f8
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * A Utility class for converting between raw binary strings and a given
+ * list of characters
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Core;
+
+/**
+ * A Utility class for converting between raw binary strings and a given
+ * list of characters
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class BaseConverter {
+
+    /**
+     * Convert from a raw binary string to a string of characters
+     *
+     * @param string $string     The string to convert from
+     * @param string $characters The list of characters to convert to
+     *
+     * @return string The converted string
+     */
+    public static function convertFromBinary($string, $characters) {
+        if ($string === '' || empty($characters)) {
+            return '';
+        }
+        $string   = str_split($string);
+        $callback = function($str) {
+                return ord($str);
+            };
+        $string    = array_map($callback, $string);
+        $converted = static::baseConvert($string, 256, strlen($characters));
+        $callback  = function ($num) use ($characters) {
+                return $characters[$num];
+            };
+        $ret = implode('', array_map($callback, $converted));
+        return $ret;
+    }
+
+    /**
+     * Convert to a raw binary string from a string of characters
+     *
+     * @param string $string     The string to convert from
+     * @param string $characters The list of characters to convert to
+     *
+     * @return string The converted string
+     */
+    public static function convertToBinary($string, $characters) {
+        if (empty($string) || empty($characters)) {
+            return '';
+        }
+        $string   = str_split($string);
+        $callback = function($str) use ($characters) {
+                return strpos($characters, $str);
+            };
+        $string    = array_map($callback, $string);
+        $converted = static::baseConvert($string, strlen($characters), 256);
+        $callback  = function ($num) {
+                return chr($num);
+            };
+        return implode('', array_map($callback, $converted));
+    }
+
+    /**
+     * Convert an array of input blocks to another numeric base
+     *
+     * This function was modified from an implementation found on StackOverflow.
+     * Special Thanks to @KeithRandall for supplying the implementation.
+     *
+     * @param int[] $source  The source number, as an array
+     * @param int   $srcBase The source base as an integer
+     * @param int   $dstBase The destination base as an integer
+     *
+     * @see http://codegolf.stackexchange.com/questions/1620/arb/1626#1626
+     * @return int[] An array of integers in the encoded base
+     */
+    public static function baseConvert(array $source, $srcBase, $dstBase) {
+        if ($dstBase < 2) {
+            $message = sprintf('Invalid Destination Base: %d', $dstBase);
+            throw new \InvalidArgumentException($message);
+        }
+        $result = array();
+        $count  = count($source);
+        while ($count) {
+            $itMax     = $count;
+            $remainder = $count = $i = 0;
+            while($i < $itMax) {
+                $dividend  = $source[$i++] + $remainder * $srcBase;
+                $remainder = $dividend % $dstBase;
+                $res       = ($dividend - $remainder) / $dstBase;
+                if ($count || $res) {
+                    $source[$count++] = $res;
+                }
+            }
+            $result[] = $remainder;
+        }
+        return array_reverse($result);
+    }
+
+}
diff --git a/CryptLib/Core/BigMath.php b/CryptLib/Core/BigMath.php
new file mode 100644 (file)
index 0000000..2c09304
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+/**
+ * A class for arbitrary precision math functions
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Core;
+
+/**
+ * A class for arbitrary precision math functions
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class BigMath {
+
+    /**
+     * Get an instance of the big math class
+     *
+     * This is NOT a singleton.  It simply loads the proper strategy
+     * given the current server configuration
+     *
+     * @return \CryptLib\Core\BigMath A big math instance
+     */
+    public static function createFromServerConfiguration() {
+        //@codeCoverageIgnoreStart
+        if (extension_loaded('bcmath')) {
+            return new \CryptLib\Core\BigMath\BCMath();
+        } elseif (extension_loaded('gmp')) {
+            return new \CryptLib\Core\BigMath\GMP();
+        } else {
+            return new \CryptLib\Core\BigMath\PHPMath();
+        }
+        //@codeCoverageIgnoreEnd
+    }
+
+    /**
+     * Add two numbers together
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return A base-10 string of the sum of the two arguments
+     */
+    abstract public function add($left, $right);
+
+    /**
+     * Subtract two numbers
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return A base-10 string of the difference of the two arguments
+     */
+    abstract public function subtract($left, $right);
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/BigMath/BCMath.php b/CryptLib/Core/BigMath/BCMath.php
new file mode 100644 (file)
index 0000000..96fee59
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * A class for arbitrary precision math functions implemented using bcmath
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Core\BigMath;
+
+/**
+ * A class for arbitrary precision math functions implemented using bcmath
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ */
+class BCMath extends \CryptLib\Core\BigMath {
+
+    /**
+     * Add two numbers together
+     * 
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     * 
+     * @return A base-10 string of the sum of the two arguments
+     */
+    public function add($left, $right) {
+        return bcadd($left, $right, 0);
+    }
+
+    /**
+     * Subtract two numbers
+     * 
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     * 
+     * @return A base-10 string of the difference of the two arguments
+     */
+    public function subtract($left, $right) {
+        return bcsub($left, $right);
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/BigMath/GMP.php b/CryptLib/Core/BigMath/GMP.php
new file mode 100644 (file)
index 0000000..4b8edbe
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * A class for arbitrary precision math functions implemented using GMP
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Core\BigMath;
+
+/**
+ * A class for arbitrary precision math functions implemented using GMP
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ */
+class GMP extends \CryptLib\Core\BigMath {
+
+    /**
+     * Add two numbers together
+     * 
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     * 
+     * @return A base-10 string of the sum of the two arguments
+     */
+    public function add($left, $right) {
+        return gmp_strval(gmp_add($left, $right));
+    }
+
+    /**
+     * Subtract two numbers
+     * 
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     * 
+     * @return A base-10 string of the difference of the two arguments
+     */
+    public function subtract($left, $right) {
+        return gmp_strval(gmp_sub($left, $right));
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/BigMath/PHPMath.php b/CryptLib/Core/BigMath/PHPMath.php
new file mode 100644 (file)
index 0000000..10bb2c5
--- /dev/null
@@ -0,0 +1,170 @@
+<?php
+/**
+ * A class for arbitrary precision math functions implemented in PHP
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Core\BigMath;
+
+use CryptLib\Core\BaseConverter;
+
+/**
+ * A class for arbitrary precision math functions implemented in PHP
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @subpackage BigMath
+ */
+class PHPMath extends \CryptLib\Core\BigMath {
+
+    /**
+     * Add two numbers together
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return A base-10 string of the sum of the two arguments
+     */
+    public function add($left, $right) {
+        if (empty($left)) {
+            return $right;
+        } elseif (empty($right)) {
+            return $left;
+        }
+        $negative = '';
+        if ($left[0] == '-' && $right[0] == '-') {
+            $negative = '-';
+            $left     = substr($left, 1);
+            $right    = substr($right, 1);
+        } elseif ($left[0] == '-') {
+            return $this->subtract($right, substr($left, 1));
+        } elseif ($right[0] == '-') {
+            return $this->subtract($left, substr($right, 1));
+        }
+        $left   = $this->normalize($left);
+        $right  = $this->normalize($right);
+        $result = BaseConverter::convertFromBinary(
+            $this->addBinary($left, $right),
+            '0123456789'
+        );
+        return $negative . $result;
+    }
+
+    /**
+     * Subtract two numbers
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return A base-10 string of the difference of the two arguments
+     */
+    public function subtract($left, $right) {
+        if (empty($left)) {
+            return $right;
+        } elseif (empty($right)) {
+            return $left;
+        } elseif ($right[0] == '-') {
+            return $this->add($left, substr($right, 1));
+        } elseif ($left[0] == '-') {
+            return '-' . $this->add(ltrim($left, '-'), $right);
+        }
+        $left    = $this->normalize($left);
+        $right   = $this->normalize($right);
+        $results = $this->subtractBinary($left, $right);
+        $result  = BaseConverter::convertFromBinary($results[1], '0123456789');
+        return $results[0] . $result;
+    }
+
+    /**
+     * Add two binary strings together
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return string The binary result
+     */
+    protected function addBinary($left, $right) {
+        $len    = max(strlen($left), strlen($right));
+        $left   = str_pad($left, $len, chr(0), STR_PAD_LEFT);
+        $right  = str_pad($right, $len, chr(0), STR_PAD_LEFT);
+        $result = '';
+        $carry  = 0;
+        for ($i = 0; $i < $len; $i++) {
+            $sum     = ord($left[$len - $i - 1])
+                 + ord($right[$len - $i - 1])
+                 + $carry;
+            $result .= chr($sum % 256);
+            $carry   = $sum >> 8;
+        }
+        while ($carry) {
+            $result .= chr($carry % 256);
+            $carry >>= 8;
+        }
+        return strrev($result);
+    }
+
+    /**
+     * Subtract two binary strings using 256's compliment
+     *
+     * @param string $left  The left argument
+     * @param string $right The right argument
+     *
+     * @return string The binary result
+     */
+    protected function subtractBinary($left, $right) {
+        $len    = max(strlen($left), strlen($right));
+        $left   = str_pad($left, $len, chr(0), STR_PAD_LEFT);
+        $right  = str_pad($right, $len, chr(0), STR_PAD_LEFT);
+        $right  = $this->compliment($right);
+        $result = $this->addBinary($left, $right);
+        if (strlen($result) > $len) {
+            // Positive Result
+            $carry  = substr($result, 0, -1 * $len);
+            $result = substr($result, strlen($carry));
+            return array(
+                '',
+                $this->addBinary($result, $carry)
+            );
+        }
+        return array('-', $this->compliment($result));
+    }
+
+    /**
+     * Take the 256 base compliment
+     *
+     * @param string $string The binary string to compliment
+     *
+     * @return string The complimented string
+     */
+    protected function compliment($string) {
+        $result = '';
+        $len    = strlen($string);
+        for ($i = 0; $i < $len; $i++) {
+            $result .= chr(255 - ord($string[$i]));
+        }
+        return $result;
+    }
+
+    /**
+     * Transform a string number into a binary string using base autodetection
+     *
+     * @param string $string The string to transform
+     *
+     * @return string The binary transformed number
+     */
+    protected function normalize($string) {
+        return BaseConverter::convertToBinary(
+            $string,
+            '0123456789'
+        );
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/Enum.php b/CryptLib/Core/Enum.php
new file mode 100644 (file)
index 0000000..13f413c
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/**
+ * The Enum base class for Enum functionality
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Core;
+
+use \ReflectionObject;
+
+/**
+ * The Enum base class for Enum functionality
+ *
+ * This is based off of the SplEnum class implementation (which is only available
+ * as a PECL extension in 5.3)
+ *
+ * @see        http://www.php.net/manual/en/class.splenum.php
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class Enum {
+
+    /**
+     * A default value of null is provided.  Override this to set your own default
+     */
+    const __DEFAULT = null;
+
+    /**
+     * @var string The name of the constant this instance is using
+     */
+    protected $name = '';
+
+    /**
+     * @var scalar The value of the constant this instance is using.
+     */
+    protected $value = '';
+
+    /**
+     * Creates a new value of the Enum type
+     *
+     * @param mixed   $value  The value this instance represents
+     * @param boolean $strict Not Implemented at this time
+     *
+     * @return void
+     * @throws UnexpectedValueException If the value is not a constant
+     */
+    public function __construct($value = null, $strict = false) {
+        if (is_null($value)) {
+            $value = static::__DEFAULT;
+        }
+        $validValues = $this->getConstList();
+        $this->name  = array_search($value, $validValues);
+        if (!$this->name) {
+            throw new \UnexpectedValueException(
+                'Value not a const in enum ' . get_class($this)
+            );
+        }
+        $this->value = $value;
+    }
+
+    /**
+     * Cast the current object to a string and return its value
+     *
+     * @return mixed the current value of the instance
+     */
+    public function __toString() {
+        return (string) $this->value;
+    }
+
+    /**
+     * Compare two enums using numeric comparison
+     *
+     * @param Enum $arg The enum to compare this instance to
+     *
+     * @return int 0 if same, 1 if the argument is greater, -1 else
+     */
+    public function compare(Enum $arg) {
+        if ($this->value == $arg->value) {
+            return 0;
+        } elseif ($this->value > $arg->value) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Returns all constants (including values) as an associative array
+     *
+     * @param boolean $include_default Include the __default magic value?
+     *
+     * @return array All of the constants found against this instance
+     */
+    public function getConstList($include_default = false) {
+        static $constCache = array();
+        $class             = get_class($this);
+        if (!isset($constCache[$class])) {
+            $reflector          = new ReflectionObject($this);
+            $constCache[$class] = $reflector->getConstants();
+        }
+        if (!$include_default) {
+            $constants = $constCache[$class];
+            unset($constants['__DEFAULT']);
+            return $constants;
+        }
+        return $constCache[$class];
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Core/Strength.php b/CryptLib/Core/Strength.php
new file mode 100644 (file)
index 0000000..60c5372
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * The strength FlyweightEnum class
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Core;
+
+/**
+ * The strength FlyweightEnum class
+ *
+ * All mixing strategies must extend this class
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Strength extends Enum {
+
+    /**
+     * We provide a default value of VeryLow so that we don't accidentally over
+     * state the strength if we forget to pass in a value...
+     */
+    const __DEFAULT = self::VERYLOW;
+
+    /**
+     * This represents Non-Cryptographic strengths.  It should not be used any time
+     * that security or confidentiality is at stake
+     */
+    const VERYLOW = 1;
+
+    /**
+     * This represents the bottom line of Cryptographic strengths.  It may be used
+     * for low security uses where some strength is required.
+     */
+    const LOW = 3;
+
+    /**
+     * This is the general purpose Cryptographical strength.  It should be suitable
+     * for all uses except the most sensitive.
+     */
+    const MEDIUM = 5;
+
+    /**
+     * This is the highest strength available.  It should not be used unless the
+     * high strength is needed, due to hardware constraints (and entropy
+     * limitations).
+     */
+    const HIGH = 7;
+
+}
diff --git a/CryptLib/CryptLib.php b/CryptLib/CryptLib.php
new file mode 100644 (file)
index 0000000..6110450
--- /dev/null
@@ -0,0 +1,164 @@
+<?php
+/**
+ * A core wrapper class to provide easy access to all of the cryptographic functions
+ * contained within the library
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib;
+
+/**
+ * The autoloader class will be autoloaded at this point even if another autoloader
+ * is in use.  So if it does not exist at this point, we know we must bootstrap
+ * the libraries.
+ */
+if (!class_exists('\\CryptLib\Core\AutoLoader', true)) {
+    require_once 'bootstrap.php';
+}
+
+use CryptLib\Password\Factory as PasswordFactory;
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * A core wrapper class to provide easy access to some of the cryptographic
+ * functions contained within the library
+ *
+ * @category   PHPCryptLib
+ * @package    Core
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class CryptLib {
+
+    /**
+     * Create a password hash from the supplied password and generator prefix
+     *
+     * @param string $password The password to hash
+     * @param string $prefix   The prefix of the hashing function
+     *
+     * @return string The generated password hash
+     */
+    public function createPasswordHash($password, $prefix = '$2a$') {
+        $factory = new PasswordFactory();
+        return $factory->createHash($password, $prefix);
+    }
+
+    /**
+     * Verify a password against a supplied password hash
+     *
+     * @param string $password The supplied password to attempt to verify
+     * @param string $hash     The valid hash to verify against
+     *
+     * @return boolean Is the password valid
+     */
+    public function verifyPasswordHash($password, $hash) {
+        $factory = new PasswordFactory();
+        return $factory->verifyHash($password, $hash);
+    }
+
+    /**
+     * Get a random element from the array
+     *
+     * @param array $sourceArray The source array to fetch from
+     *
+     * @return mixed A random element from the source array
+     */
+    public function getRandomArrayElement(array $sourceArray) {
+        $keys       = array_keys($sourceArray);
+        $upperBound = count($keys);
+        $factory    = new RandomFactory;
+        $generator  = $factory->getMediumStrengthGenerator();
+        $key        = $generator->generateInt(0, $upperBound - 1);
+        return $sourceArray[$keys[$key]];
+    }
+
+    /**
+     * Generate a random full-byte string (characters 0 - 255)
+     *
+     * @param int $size The length of the generated string
+     *
+     * @return string The generated string
+     */
+    public function getRandomBytes($size) {
+        $factory   = new RandomFactory;
+        $generator = $factory->getMediumStrengthGenerator();
+        return $generator->generate($size);
+    }
+
+    /**
+     * Get a random number between the supplied boundaries
+     *
+     * @param int $min The smallest bound the generated number can be
+     * @param int $max The upper bound on the generated number
+     *
+     * @return int The generated random number
+     */
+    public function getRandomNumber($min = 0, $max = PHP_INT_MAX) {
+        $factory   = new RandomFactory;
+        $generator = $factory->getMediumStrengthGenerator();
+        return $generator->generateInt($min, $max);
+    }
+
+    /**
+     * Generate a random token using base64 characters (a-zA-Z0-9./)
+     *
+     * @param int $size The number of characters in the generated output
+     *
+     * @return string The generated token string
+     */
+    public function getRandomToken($size) {
+        $factory   = new RandomFactory;
+        $generator = $factory->getMediumStrengthGenerator();
+        return $generator->generateString($size);
+    }
+
+    /**
+     * Shuffle an array.  This will preserve key => value relationships, and return
+     * a new array that has been randomized in order.
+     *
+     * To get keys randomized, simply pass the result through array_values()...
+     *
+     * @param array $array The input array to randomize
+     *
+     * @return array The suffled array
+     */
+    public function shuffleArray(array $array) {
+        $factory   = new RandomFactory;
+        $generator = $factory->getMediumStrengthGenerator();
+        $result    = array();
+        $values    = array_values($array);
+        $keys      = array_keys($array);
+        $max       = count($array);
+        for ($i = $max - 1; $i >= 0; $i--) {
+            $int                 = $generator->generateInt(0, $i);
+            $result[$keys[$int]] = $values[$int];
+            unset($keys[$int], $values[$int]);
+            $keys   = array_values($keys);
+            $values = array_values($values);
+        }
+        return $result;
+    }
+
+    /**
+     * Shuffle a string and return the randomized string
+     *
+     * @param string $string The string to randomize
+     *
+     * @return string The shuffled string
+     */
+    public function shuffleString($string) {
+        $factory   = new RandomFactory;
+        $generator = $factory->getMediumStrengthGenerator();
+        $array     = str_split($string);
+        $result    = $this->shuffleArray($array);
+        return implode('', $result);
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Encryption/Factory.php b/CryptLib/Encryption/Factory.php
new file mode 100644 (file)
index 0000000..1197d94
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * The core Encryption Factory
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption;
+
+use CryptLib\Cipher\Factory as CipherFactory;
+
+/**
+ * The core Encryption Factory
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Factory extends \CryptLib\Core\AbstractFactory {
+
+    /**
+     * @var Factory The Cipher Factory to use for this instance
+     */
+    protected $cipherFactory = null;
+
+    /**
+     * @var array An array of PackingModes available for use
+     */
+    protected $packingModes = array();
+
+    /**
+     * Build the instance
+     *
+     * @param Factory $factory The Cipher Factory to use for this instance
+     *
+     * @return void
+     */
+    public function __construct(CryptoLib\Cipher\Factory $factory = null) {
+        if (is_null($factory)) {
+            $factory = new CipherFactory();
+        }
+        $this->cipherFactory = $factory;
+        $this->loadPackingModes();
+    }
+
+    /**
+     * Get a packing mode by name
+     *
+     * @param string|PackingMode $name The name of the packing mode or instance
+     *
+     * @return PackingMode The instantiated PackingMode class
+     * @throws RuntimeException If the mode does not exist
+     */
+    public function getPackingMode($name) {
+        if (is_object($name) && $name instanceof PackingMode) {
+            return $name;
+        }
+        $name = strtolower($name);
+        if (isset($this->packingModes[$name])) {
+            $class = $this->packingModes[$name];
+            return new $class;
+        }
+        $message = sprintf('Invalid Mode Supplied: %s', $name);
+        throw new \RuntimeException($message);
+    }
+
+    /**
+     * Register a new packing mode by name
+     *
+     * @param string $name  The name of the packing mode
+     * @param string $class The class to instantiate for the mode
+     *
+     * @return Factory $this The current factory instance
+     */
+    public function registerPackingMode($name, $class) {
+        $this->registerType(
+            'packingModes',
+            __NAMESPACE__ . '\\PackingMode',
+            $name,
+            $class
+        );
+        return $this;
+    }
+
+    /**
+     * Load the core packing modes for this instance
+     *
+     * @return void
+     */
+    protected function loadPackingModes() {
+        $this->loadFiles(
+            __DIR__ . '/PackingMode',
+            __NAMESPACE__ . '\\PackingMode\\',
+            array($this, 'registerPackingMode')
+        );
+    }
+
+}
diff --git a/CryptLib/Encryption/PackingMode.php b/CryptLib/Encryption/PackingMode.php
new file mode 100644 (file)
index 0000000..7254ab5
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The core PackingMode interface.  All packingmodes must implement this
+ * interface
+ *
+ * A packing mode is a method for padding a string to a specified size using
+ * various methods
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption;
+
+/**
+ * The core PackingMode interface.  All packingmodes must implement this
+ * interface
+ *
+ * A packing mode is a method for padding a string to a specified size using
+ * various methods
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32);
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string);
+
+}
+
diff --git a/CryptLib/Encryption/PackingMode/ANSIx923.php b/CryptLib/Encryption/PackingMode/ANSIx923.php
new file mode 100644 (file)
index 0000000..8e5d146
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * A packing mode implementation for ASNIx923 padding
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption\PackingMode;
+
+/**
+ * A packing mode implementation for ASNIx923 padding
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class ANSIx923 implements \CryptLib\Encryption\PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32) {
+        $pad = $blockSize - (strlen($string) % $blockSize);
+        return $string . str_repeat(chr(0), $pad - 1) . chr($pad);
+    }
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string) {
+        $end = ord(substr($string, -1));
+        $len = strlen($string) - $end;
+        $tmp = str_repeat(chr(0), $end - 1) . chr($end);
+        if (substr($string, $len) == $tmp) {
+            return substr($string, 0, $len);
+        }
+        return false;
+    }
+
+}
diff --git a/CryptLib/Encryption/PackingMode/ISO10126.php b/CryptLib/Encryption/PackingMode/ISO10126.php
new file mode 100644 (file)
index 0000000..bd89015
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * A Packing Mode implementation of the ISO 10126 standard
+ *
+ * PHP version 5.3
+ * 
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption\PackingMode;
+
+/**
+ * A Packing Mode implementation of the ISO 10126 standard
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class ISO10126 implements \CryptLib\Encryption\PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32) {
+        $pad    = $blockSize - (strlen($string) % $blockSize);
+        $padstr = '';
+        for ($i = 1; $i < $pad; $i++) {
+            $padstr .= chr(mt_rand(0, 255));
+        }
+        return $string . $padstr . chr($pad);
+    }
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string) {
+        $end = ord(substr($string, -1));
+        $len = strlen($string) - $end;
+        return substr($string, 0, $len);
+    }
+
+}
diff --git a/CryptLib/Encryption/PackingMode/None.php b/CryptLib/Encryption/PackingMode/None.php
new file mode 100644 (file)
index 0000000..95cb376
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * A packing mode implementation for no padding
+ *
+ * This is provided for completeness only.  Do not use this with actual ciphers
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption\PackingMode;
+
+/**
+ * A packing mode implementation for no padding
+ *
+ * This is provided for completeness only.  Do not use this with actual ciphers
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class None implements \CryptLib\Encryption\PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32) {
+        return $string;
+    }
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string) {
+        return $string;
+    }
+
+}
diff --git a/CryptLib/Encryption/PackingMode/PKCS7.php b/CryptLib/Encryption/PackingMode/PKCS7.php
new file mode 100644 (file)
index 0000000..603e4fb
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * A packing mode implementation for PKCS7 padding
+ *
+ * PHP version 5.3
+ *
+ * @see        http://tools.ietf.org/html/rfc2315
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption\PackingMode;
+
+/**
+ * A packing mode implementation for PKCS7 padding
+ *
+ * PHP version 5.3
+ *
+ * @see        http://tools.ietf.org/html/rfc2315
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PKCS7 implements \CryptLib\Encryption\PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32) {
+        $pad = $blockSize - (strlen($string) % $blockSize);
+        return $string . str_repeat(chr($pad), $pad);
+    }
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string) {
+        $end  = substr($string, -1);
+        $last = ord($end);
+        $len  = strlen($string) - $last;
+        if (substr($string, $len) == str_repeat($end, $last)) {
+            return substr($string, 0, $len);
+        }
+        return false;
+    }
+
+}
diff --git a/CryptLib/Encryption/PackingMode/Zeros.php b/CryptLib/Encryption/PackingMode/Zeros.php
new file mode 100644 (file)
index 0000000..e5e6164
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * A packing mode implementation for null-byte padding
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Encryption\PackingMode;
+
+/**
+ * A packing mode implementation for null-byte padding
+ *
+ * @category   PHPCryptLib
+ * @package    Encryption
+ * @subpackage PackingMode
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Zeros implements \CryptLib\Encryption\PackingMode {
+
+    /**
+     * Pad the string to the specified size
+     *
+     * @param string $string    The string to pad
+     * @param int    $blockSize The size to pad to
+     *
+     * @return string The padded string
+     */
+    public function pad($string, $blockSize = 32) {
+        $pad = $blockSize - (strlen($string) % $blockSize);
+        if ($pad == $blockSize) {
+            return $string;
+        }
+        return $string . str_repeat(chr(0), $pad);
+    }
+
+    /**
+     * Strip the padding from the supplied string
+     *
+     * @param string $string The string to trim
+     *
+     * @return string The unpadded string
+     */
+    public function strip($string) {
+        return rtrim($string, chr(0));
+    }
+
+}
diff --git a/CryptLib/Hash/CRC32.php b/CryptLib/Hash/CRC32.php
new file mode 100644 (file)
index 0000000..2fd8352
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * An implementation of a streamable CRC32
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Hash
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Hash;
+
+/**
+ * An implementation of a streamable CRC32
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Hash
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class CRC32 {
+
+    /**
+     * @var int The initialal value for the CRC32
+     */
+    protected static $initValue = 0xFFFFFFFF;
+
+    /**
+     * @var array The table of permutations for substituting CRC32 data with
+     */
+    protected static $table = array(
+        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+        0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
+        0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+        0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+        0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+        0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
+        0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+        0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+        0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+        0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
+        0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+        0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
+        0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+        0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
+        0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+        0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
+        0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+        0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+        0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+        0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
+        0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+        0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
+    );
+
+    /**
+     * Compute a CRC32 value of a string
+     *
+     * @param string $data The data to calculate the crc32 for
+     *
+     * @return int The computed CRC32 value
+     */
+    public static function calculate($data) {
+        return static::update(static::$initValue ^ 0xFFFFFFFF, $data);
+    }
+
+    /**
+     * Updates an existing CRC32 value with a new byte (for a stream)
+     *
+     * @param int    $crc32 The previous CRC32 value
+     * @param string $data  The new byte to end (string length 1)
+     *
+     * @return int The updated CRC32 value
+     */
+    public static function update($crc32, $data) {
+        $result = $crc32 ^ 0xFFFFFFFF;
+        $length = strlen($data);
+        for ($i = 0; $i < $length; $i++) {
+            $lowPart = $result & 0xFF;
+            $shifted = ($result >> 8) & 0xFFFFFF;
+            $result  = static::$table[($lowPart ^ ord($data[$i])) & 0xFF] ^ $shifted;
+        }
+        return $result ^ 0xFFFFFFFF;
+    }
+
+}
diff --git a/CryptLib/Hash/Hash.php b/CryptLib/Hash/Hash.php
new file mode 100644 (file)
index 0000000..8c6f8a6
--- /dev/null
@@ -0,0 +1,360 @@
+<?php
+/**
+ * A hash utility data mapper class
+ * 
+ * This class's purpose is to store information about hash algorithms that is
+ * otherwise unavailable during runtime.  Some information is available (such 
+ * as the output size), but is included anyway for performance and completeness
+ * reasons.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Hash
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\Hash;
+
+/**
+ * A hash utility data mapper class
+ * 
+ * This class's purpose is to store information about hash algorithms that is
+ * otherwise unavailable during runtime.  Some information is available (such 
+ * as the output size), but is included anyway for performance and completeness
+ * reasons.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Hash
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Hash {
+
+    /**
+     * This array contains information about each hash function available to PHP
+     * at the present time.  Block sizes are not available from functions, so they
+     * must be hard coded.
+     * 
+     * The "secure" indicates the strength of the hash and whether or not any known
+     * cryptographic attacks exist for the hash function. This will only apply when
+     * using the hash functions for situations that require cryptographic strength
+     * such as message signing.  For other uses the insecure ones can have valid
+     * uses.
+     * 
+     * @var array An array of information about each supported hash function 
+     */
+    protected static $hashInfo = array(
+        'md2' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 128,
+            'secure'    => false,
+        ),
+        'md4' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 512,
+            'secure'    => false,
+        ),
+        'md5' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 512,
+            'secure'    => false,
+        ),
+        'sha1' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 512,
+            'secure'    => false,
+        ),
+        'sha224' => array(
+            'HashSize'  => 224,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'sha256' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'sha384' => array(
+            'HashSize'  => 384,
+            'BlockSize' => 1024,
+            'secure'    => true,
+        ),
+        'sha512' => array(
+            'HashSize'  => 512,
+            'BlockSize' => 1024,
+            'secure'    => true,
+        ),
+        'ripemd128' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'ripemd160' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'ripemd256' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'ripemd320' => array(
+            'HashSize'  => 320,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'whirlpool' => array(
+            'HashSize'  => 512,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger128,3' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger160,3' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger192,3' => array(
+            'HashSize'  => 192,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger128,4' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger160,4' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'tiger192,4' => array(
+            'HashSize'  => 192,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'snefru' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 512,
+            'secure'    => false,
+        ),
+        'snefru256' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 512,
+            'secure'    => false,
+        ),
+        'gost' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 256,
+            'secure'    => false,
+        ),
+        'adler32' => array(
+            'HashSize'  => 32,
+            'BlockSize' => 16,
+            'secure'    => false,
+        ),
+        'crc32' => array(
+            'HashSize'  => 32,
+            'BlockSize' => 32,
+            'secure'    => false,
+        ),
+        'crc32b' => array(
+            'HashSize'  => 32,
+            'BlockSize' => 32,
+            'secure'    => false,
+        ),
+        'salsa10' => array(
+            'HashSize'  => 512,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'salsa20' => array(
+            'HashSize'  => 512,
+            'BlockSize' => 512,
+            'secure'    => true,
+        ),
+        'haval128,3' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval160,3' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval192,3' => array(
+            'HashSize'  => 192,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval224,3' => array(
+            'HashSize'  => 224,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval256,3' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval128,4' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval160,4' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval192,4' => array(
+            'HashSize'  => 192,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval224,4' => array(
+            'HashSize'  => 224,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval256,4' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval128,5' => array(
+            'HashSize'  => 128,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval160,5' => array(
+            'HashSize'  => 160,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval192,5' => array(
+            'HashSize'  => 192,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval224,5' => array(
+            'HashSize'  => 224,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'haval256,5' => array(
+            'HashSize'  => 256,
+            'BlockSize' => 1024,
+            'secure'    => false,
+        ),
+        'joaat' => array(
+            'HashSize'  => 32,
+            'BlockSize' => 64,
+            'secure'    => false,
+        ),
+        'fnv132' => array(
+            'HashSize'  => 32,
+            'BlockSize' => 32,
+            'secure'    => false,
+        ),
+        'fnv164' => array(
+            'HashSize'  => 64,
+            'BlockSize' => 64,
+            'secure'    => false,
+        ),
+    );
+
+    /**
+     * Get the block size of the specified function in bytes
+     *
+     * @param string $hash The hash function to look up
+     * 
+     * @return int The number of bytes in the block function
+     */
+    public static function getBlockSize($hash) {
+        return static::getBlockSizeInBits($hash) / 8;
+    }
+
+    /**
+     * Get the block size of the specified function in bits
+     *
+     * @param string $hash The hash function to look up
+     * 
+     * @return int The number of bits in the block function
+     */
+    public static function getBlockSizeInBits($hash) {
+        if (isset(static::$hashInfo[$hash]['BlockSize'])) {
+            return static::$hashInfo[$hash]['BlockSize'];
+        }
+        return 0;
+    }
+
+    /**
+     * Get the output size of the specified function in bytes
+     *
+     * @param string $hash The hash function to look up
+     * 
+     * @return int The number of bytes outputted by the hash function
+     */
+    public static function getHashSize($hash) {
+        return static::getHashSizeInBits($hash) / 8;
+    }
+
+    /**
+     * Get the output size of the specified function in bits
+     *
+     * @param string $hash The hash function to look up
+     * 
+     * @return int The number of bits outputted by the hash function
+     */
+    public static function getHashSizeInBits($hash) {
+        if (isset(static::$hashInfo[$hash]['HashSize'])) {
+            return static::$hashInfo[$hash]['HashSize'];
+        }
+        return 0;
+    }
+
+    /**
+     * Check to see if the hash function specified is available
+     *
+     * @param string $hash The hash function to look up
+     * 
+     * @return boolean If the hash function is available in this version of PHP
+     */
+    public static function isAvailable($hash) {
+        return in_array($hash, hash_algos());
+    }
+
+    /**
+     * Check to see if the specified hash function is secure enough for 
+     * cryptographic uses
+     * 
+     * The "secure" indicates the strength of the hash and whether or not any known
+     * cryptographic attacks exist for the hash function. This will only apply when
+     * using the hash functions for situations that require cryptographic strength
+     * such as message signing.  For other uses the insecure ones can have valid
+     * uses.
+     * 
+     * @param string $hash The hash function to look up
+     * 
+     * @return bolean If the function is secure
+     */
+    public static function isSecure($hash) {
+        if (isset(static::$hashInfo[$hash])) {
+            return static::$hashInfo[$hash]['secure'];
+        }
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Key/Derivation/AbstractDerivation.php b/CryptLib/Key/Derivation/AbstractDerivation.php
new file mode 100644 (file)
index 0000000..775a082
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * An abstract implementation of some standard key derivation needs
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation;
+
+/**
+ * An abstract implementation of some standard key derivation needs
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class AbstractDerivation {
+
+    /**
+     * @var Hash A hashing algorithm to use for the derivation
+     */
+    protected $hash = null;
+
+    /**
+     * @var array An array of options for the key derivation function
+     */
+    protected $options = array(
+        'hash'        => 'sha512',
+    );
+
+    /**
+     * Construct the derivation instance
+     *
+     * @param array $options An array of options to set for this instance
+     *
+     * @return void
+     */
+    public function __construct(array $options = array()) {
+        $this->options = $options + $this->options;
+        $this->hash    = $this->options['hash'];
+    }
+
+}
diff --git a/CryptLib/Key/Derivation/KDF.php b/CryptLib/Key/Derivation/KDF.php
new file mode 100644 (file)
index 0000000..5d7a26e
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * The standard Key Derivation Function interface
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT Licenses
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation;
+
+/**
+ * The standard Key Derivation Function interface
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface KDF {
+
+    /**
+     * Derive a key of the specified length based on the inputted secret
+     *
+     * @param string $secret The secret to base the key on
+     * @param int    $length The length of the key to derive
+     * @param string $other  Additional data to append to the key
+     *
+     * @return string The generated key
+     */
+    public function derive($secret, $length, $other = '');
+
+}
diff --git a/CryptLib/Key/Derivation/KDF/KDF1.php b/CryptLib/Key/Derivation/KDF/KDF1.php
new file mode 100644 (file)
index 0000000..0f45423
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * An implementation of the RFC 10833-2 KDF1 Standard key derivation function
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\KDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * An implementation of the RFC 10833-2 KDF1 Standard key derivation function
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class KDF1
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\KDF
+{
+
+    /**
+     * Derive a key of the specified length based on the inputted secret
+     *
+     * @param string $secret The secret to base the key on
+     * @param int    $length The length of the key to derive
+     * @param string $other  Additional data to append to the key
+     *
+     * @return string The generated key
+     */
+    public function derive($secret, $length, $other = '') {
+        $size = Hash::getHashSize($this->hash);
+        $len  = ceil($length / $size);
+        $res  = '';
+        for ($i = 0; $i < $len; $i++) {
+            $tmp  = pack('N', $i);
+            $res .= hash($this->hash, $secret . $tmp . $other, true);
+        }
+        return substr($res, 0, $length);
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/KDF/KDF2.php b/CryptLib/Key/Derivation/KDF/KDF2.php
new file mode 100644 (file)
index 0000000..4bd3464
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * An implementation of the RFC 10833-2 KDF2 Standard key derivation function
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\KDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * An implementation of the RFC 10833-2 KDF2 Standard key derivation function
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class KDF2
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\KDF
+{
+
+    /**
+     * Derive a key of the specified length based on the inputted secret
+     *
+     * @param string $secret The secret to base the key on
+     * @param int    $length The length of the key to derive
+     * @param string $other  Additional data to append to the key
+     *
+     * @return string The generated key
+     */
+    public function derive($secret, $length, $other = '') {
+        $size = Hash::getHashSize($this->hash);
+        $len  = ceil($length / $size);
+        $res  = '';
+        for ($i = 1; $i <= $len; $i++) {
+            $tmp  = pack('N', $i);
+            $res .= hash($this->hash, $secret . $tmp . $other, true);
+        }
+        return substr($res, 0, $length);
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/KDF/KDF3.php b/CryptLib/Key/Derivation/KDF/KDF3.php
new file mode 100644 (file)
index 0000000..90d3d6e
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * An implementation of the RFC 10833-2 KDF3 Standard key derivation function
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\KDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * An implementation of the RFC 10833-2 KDF3 Standard key derivation function
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class KDF3
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\KDF
+{
+
+    /**
+     * @var array An array of options for the key derivation function
+     */
+    protected $options = array(
+        'hash'        => 'sha512',
+        'pAmt'        => 4,
+    );
+
+    /**
+     * Derive a key of the specified length based on the inputted secret
+     *
+     * @param string $secret The secret to base the key on
+     * @param int    $length The length of the key to derive
+     * @param string $other  Additional data to append to the key
+     *
+     * @return string The generated key
+     */
+    public function derive($secret, $length, $other = '') {
+        $size = Hash::getHashSize($this->hash);
+        $len  = ceil($length / $size);
+        $res  = '';
+        $stub = str_repeat(chr(0), max($this->options['pAmt'], 0));
+        for ($i = 0; $i < $len; $i++) {
+            $tmp  = $stub . pack('N', $i);
+            $res .= hash($this->hash, $tmp . $secret . $other, true);
+        }
+        return substr($res, 0, $length);
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF.php b/CryptLib/Key/Derivation/PBKDF.php
new file mode 100644 (file)
index 0000000..6275b2f
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+/**
+ * The core PBKDF interface (Password Based Key Derivation Function)
+ *
+ * This interface must be used to describe all derivation functions that take a
+ * password as input and produce a key or hash as output 
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation;
+
+/**
+ * The core PBKDF interface (Password Based Key Derivation Function)
+ *
+ * This interface must be used to describe all derivation functions that take a
+ * password as input and produce a key or hash as output
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface PBKDF {
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($passkey, $salt, $iterations, $klen);
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature();
+
+}
diff --git a/CryptLib/Key/Derivation/PBKDF/BCrypt.php b/CryptLib/Key/Derivation/PBKDF/BCrypt.php
new file mode 100644 (file)
index 0000000..94abd40
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+/**
+ * An implementation of the crypt library's Blowfish hash method
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+/**
+ * An implementation of the crypt library's Blowfish hash method
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class BCrypt
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($password, $salt, $iterations, $length) {
+        $salt = $this->encode64($salt);
+        if (strlen($salt) > 22) {
+            $salt = substr($salt, 0, 22);
+        } elseif (strlen($salt) < 22) {
+            $salt = str_pad($salt, '0');
+        }
+        $expense = ceil(log($iterations, 2));
+        $expense = $expense < 4 ? 4 : $expense;
+        $expense = $expense > 31 ? 31 : $expense;
+        $salt    = '$2a$'.str_pad($expense, 2, '0', STR_PAD_LEFT).'$'.$salt;
+        return crypt($password, $salt);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'bcrypt';
+    }
+
+    /**
+     * Encode a string for a blowfish salt
+     *
+     * @param string $string The string to encode
+     *
+     * @return The encoded string
+     */
+    protected function encode64($string) {
+        return str_replace(
+            array('+', '='),
+            array('.', '/'),
+            base64_encode($string)
+        );
+    }
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF/PBKDF1.php b/CryptLib/Key/Derivation/PBKDF/PBKDF1.php
new file mode 100644 (file)
index 0000000..9f8caa6
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * An implementation of the RFC 2898 PBKDF1 Standard key derivation function
+ *
+ * PHP version 5.3
+ *
+ * @see        http://www.ietf.org/rfc/rfc2898.txt
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * An implementation of the RFC 2989 PBKDF1 Standard key derivation function
+ *
+ * @see        http://www.ietf.org/rfc/rfc2898.txt
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PBKDF1
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($password, $salt, $iterations, $length) {
+        $size = Hash::getHashSize($this->hash);
+        if ($length > $size) {
+            $message = 'Length is too long for hash';
+            throw new \InvalidArgumentException($message);
+        }
+        $tmp = hash($this->hash, $password . $salt, true);
+        for ($i = 2; $i <= $iterations; $i++) {
+            $tmp = hash($this->hash, $tmp, true);
+        }
+        return substr($tmp, 0, $length);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'pbkdf1-' . $this->hash;
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF/PBKDF2.php b/CryptLib/Key/Derivation/PBKDF/PBKDF2.php
new file mode 100644 (file)
index 0000000..99a011e
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * An implementation of the RFC 2898 PBKDF2 Standard key derivation function
+ *
+ * PHP version 5.3
+ *
+ * @see        http://www.ietf.org/rfc/rfc2898.txt
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * An implementation of the RFC 2898 PBKDF2 Standard key derivation function
+ *
+ * @see        http://www.ietf.org/rfc/rfc2898.txt
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PBKDF2
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($password, $salt, $iterations, $length) {
+        $size   = Hash::getHashSize($this->hash);
+        $len    = ceil($length / $size);
+        $result = '';
+        for ($i = 1; $i <= $len; $i++) {
+            $tmp = hash_hmac(
+                $this->hash,
+                $salt . pack('N', $i),
+                $password,
+                true
+            );
+            $res = $tmp;
+            for ($j = 1; $j < $iterations; $j++) {
+                $tmp  = hash_hmac($this->hash, $tmp, $password, true);
+                $res ^= $tmp;
+            }
+            $result .= $res;
+        }
+        return substr($result, 0, $length);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'pbkdf2-' . $this->hash;
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF/SHA256.php b/CryptLib/Key/Derivation/PBKDF/SHA256.php
new file mode 100644 (file)
index 0000000..a86f8dc
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/**
+ * An implementation of the crypt library's SHA512 hash method
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+/**
+ * An implementation of the crypt library's SHA512 hash method
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class SHA256
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($password, $salt, $iterations, $length) {
+        $salt = substr(str_pad($salt, 16, chr(0)), 0, 16);
+        $salt = '$5$rounds='.$iterations.'$'.$salt;
+        return crypt($password, $salt);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'sha256';
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF/SHA512.php b/CryptLib/Key/Derivation/PBKDF/SHA512.php
new file mode 100644 (file)
index 0000000..8d710e2
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/**
+ * An implementation of the crypt library's SHA512 hash method
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+/**
+ * An implementation of the crypt library's SHA512 hash method
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @subpackage Derivation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class SHA512
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    /**
+     * Derive a key from the supplied arguments
+     *
+     * @param string $password   The password to derive from
+     * @param string $salt       The salt string to use
+     * @param int    $iterations The number of iterations to use
+     * @param int    $length     The size of the string to generate
+     *
+     * @return string The derived key
+     */
+    public function derive($password, $salt, $iterations, $length) {
+        $salt = substr(str_pad($salt, 16, chr(0)), 0, 16);
+        $salt = '$6$rounds='.$iterations.'$'.$salt;
+        return crypt($password, $salt);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same isntance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'sha512';
+    }
+
+}
+
diff --git a/CryptLib/Key/Derivation/PBKDF/Schneier.php b/CryptLib/Key/Derivation/PBKDF/Schneier.php
new file mode 100644 (file)
index 0000000..b3a7c74
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Derivation\PBKDF;
+
+use CryptLib\Hash\Hash;
+
+/**
+ * Description of pbkdf2
+ *
+ * @author ircmaxell
+ */
+class Schneier
+    extends \CryptLib\Key\Derivation\AbstractDerivation
+    implements \CryptLib\Key\Derivation\PBKDF
+{
+
+    public function derive($password, $salt, $iterations, $length) {
+        $size = Hash::getHashSize($this->hash);
+        if ($length > $size) {
+            throw new \InvalidArgumentException('Length is too long for hash');
+        }
+        $tmp = hash($this->hash, $password . $salt, true);
+        for ($i = 2; $i <= $iterations; $i++) {
+            $tmp = hash($this->hash, $tmp . $password . $salt, true);
+        }
+        return substr($tmp, 0, $length);
+    }
+
+    /**
+     * Get the signature for this implementation
+     *
+     * This should include all information needed to build the same instance
+     * later.
+     *
+     * @return string The signature for this instance
+     */
+    public function getSignature() {
+        return 'schneier-'.$this->hash;
+    }
+
+}
diff --git a/CryptLib/Key/Factory.php b/CryptLib/Key/Factory.php
new file mode 100644 (file)
index 0000000..e9ae3ea
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/**
+ * The core Key Factory
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key;
+
+/**
+ * The core Key Factory
+ *
+ * @category   PHPCryptLib
+ * @package    Key
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Factory extends \CryptLib\Core\AbstractFactory {
+
+    /**
+     * @var array An array of KDF class implementations
+     */
+    protected $kdf = array();
+
+    /**
+     * @var array An array of PBKDF class implementations
+     */
+    protected $pbkdf = array();
+
+    /**
+     * @var array An array of symmetric key generator implementations
+     */
+    protected $symmetricGenerators = array();
+
+    /**
+     * Construct the instance, loading the core implementations
+     *
+     * @return void
+     */
+    public function __construct() {
+        $this->loadPBKDF();
+        $this->loadKDF();
+        //$this->loadSymmetricGenerators();
+    }
+
+    public function getKDF($name = 'kdf3', array $options = array()) {
+        if (isset($this->kdf[$name])) {
+            $class = $this->kdf[$name];
+            return new $class($options);
+        }
+        throw new \InvalidArgumentException('Unsupported KDF');
+    }
+
+    public function getPBKDF($name = 'pbkdf2', array $options = array()) {
+        if (isset($this->pbkdf[$name])) {
+            $class = $this->pbkdf[$name];
+            return new $class($options);
+        }
+        throw new \InvalidArgumentException('Unsupported PBKDF');
+    }
+
+    public function getPBKDFFromSignature($signature) {
+        list ($name, $hash) = explode('-', $signature, 2);
+        return $this->getPBKDF($name, array('hash' => $hash));
+    }
+
+    public function getSymmetricKeyGenerator() {
+    }
+
+    public function registerKDF($name, $class) {
+        $this->registerType(
+            'kdf',
+            __NAMESPACE__ . '\\Derivation\\KDF',
+            $name,
+            $class
+        );
+    }
+
+    public function registerPBKDF($name, $class) {
+        $this->registerType(
+            'pbkdf',
+            __NAMESPACE__ . '\\Derivation\\PBKDF',
+            $name,
+            $class
+        );
+    }
+
+    protected function loadKDF() {
+        $this->loadFiles(
+            __DIR__ . '/Derivation/KDF',
+            __NAMESPACE__ . '\\Derivation\\KDF\\',
+            array($this, 'registerKDF')
+        );
+    }
+
+    protected function loadPBKDF() {
+        $this->loadFiles(
+            __DIR__ . '/Derivation/PBKDF',
+            __NAMESPACE__ . '\\Derivation\\PBKDF\\',
+            array($this, 'registerPBKDF')
+        );
+    }
+
+}
diff --git a/CryptLib/Key/Generator.php b/CryptLib/Key/Generator.php
new file mode 100644 (file)
index 0000000..09c5ce0
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key;
+
+/**
+ * Description of generator
+ *
+ * @author ircmaxell
+ * @codeCoverageIgnore
+ */
+interface Generator extends Key {
+
+    public static function test();
+
+    public function __construct(array $options = array());
+
+    /**
+     * Generate a key of the supplied size
+     *
+     * @param Strength $strength   The strength of the generated key
+     * @param int      $size       The size of the generated key (in bytes)
+     * @param string   $passPhrase The passphrase to encrypt the key with
+     *
+     * @return void
+     */
+    public function generate(
+        \CryptLib\Core\Strength $strength,
+        $size,
+        $passPhrase = ''
+    );
+
+}
diff --git a/CryptLib/Key/Key.php b/CryptLib/Key/Key.php
new file mode 100644 (file)
index 0000000..4551c06
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key;
+
+/**
+ *
+ * @author ircmaxell
+ * @codeCoverageIgnore
+ */
+interface Key {
+
+    const SYMMETRIC = 'symmetric';
+
+    const PUBLICKEY = 'publickey';
+
+    public function __toString();
+
+    public function getType();
+
+}
diff --git a/CryptLib/Key/Symmetric.php b/CryptLib/Key/Symmetric.php
new file mode 100644 (file)
index 0000000..49ec004
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key;
+
+/**
+ *
+ * @author ircmaxell
+ * @codeCoverageIgnore
+ */
+interface Symmetric extends Key {
+
+    public function getKey();
+
+    public function saveKey($filename);
+
+}
diff --git a/CryptLib/Key/Symmetric/AbstractSymmetric.php b/CryptLib/Key/Symmetric/AbstractSymmetric.php
new file mode 100644 (file)
index 0000000..4bbf617
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Symmetric;
+
+/**
+ * Description of abstractsymetric
+ *
+ * @author ircmaxell
+ */
+abstract class AbstractSymmetric implements \CryptLib\Key\Symmetric {
+
+    protected $key = '';
+
+    public function __toString() {
+        return $this->getKey();
+    }
+
+    public function getKey() {
+        return $this->key;
+    }
+
+    public function getType() {
+        return self::SYMMETRIC;
+    }
+
+    public function saveKey($filename) {
+        file_put_contents($filename, $this->getKey());
+    }
+
+}
diff --git a/CryptLib/Key/Symmetric/Generator/Internal.php b/CryptLib/Key/Symmetric/Generator/Internal.php
new file mode 100644 (file)
index 0000000..3c374b4
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Symmetric\Generator;
+
+use CryptLib\Random\Factory    as RandomFactory;
+use CryptLib\Key\Factory       as KeyFactory;
+use CryptLib\Key\Symmetric\Raw as Raw;
+
+/**
+ * Description of mtrand
+ *
+ * @author ircmaxell
+ */
+class Internal implements \CryptLib\Key\Generator {
+
+    protected $kdf = null;
+
+    protected $random = null;
+
+    public static function test() {
+        return true;
+    }
+
+    public function __construct(array $options = array()) {
+        $options += array('kdf' => null, 'random' => null);
+        if (is_null($options['kdf'])) {
+            $factory        = new KeyFactory();
+            $options['kdf'] = $factory->getKdf('kdf3');
+        }
+        $this->kdf = $options['kdf'];
+        if (is_null($options['random'])) {
+            $options['random'] = new RandomFactory();
+        }
+        $this->random = $options['random'];
+    }
+
+    public function __toString() {
+    }
+
+    public function generate(
+        \CryptLib\Core\Strength $strength,
+        $size,
+        $passphrase = ''
+    ) {
+        $generator = $this->random->getGenerator($strength);
+        $seed      = $generator->generate($size);
+        $key       = $this->kdf->derive($seed, $size, $passphrase);
+        return new Raw(substr($key, 0, $size));
+    }
+
+    public function getType() {
+        return static::TYPE_SYMMETRIC;
+    }
+}
diff --git a/CryptLib/Key/Symmetric/Raw.php b/CryptLib/Key/Symmetric/Raw.php
new file mode 100644 (file)
index 0000000..1d68a04
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Key\Symmetric;
+
+/**
+ * Description of raw
+ *
+ * @author ircmaxell
+ */
+class Raw extends AbstractSymmetric {
+
+    public function __construct($key) {
+        $this->key = $key;
+    }
+
+}
+
diff --git a/CryptLib/MAC/AbstractMAC.php b/CryptLib/MAC/AbstractMAC.php
new file mode 100644 (file)
index 0000000..ee8189f
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * An abstract class for MessageAuthenticationCode generation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\MAC;
+
+/**
+ * An abstract class for MessageAuthenticationCode generation
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class AbstractMAC implements MAC {
+
+    /**
+     * @var array The stored options for this instance
+     */
+    protected $options = array();
+
+    /**
+     * Build the instance of the MAC generator
+     *
+     * @param array $options The options for the instance
+     *
+     * @return void
+     */
+    public function __construct(array $options = array()) {
+        $this->options = $options + $this->options;
+    }
+
+}
diff --git a/CryptLib/MAC/Implementation/CMAC.php b/CryptLib/MAC/Implementation/CMAC.php
new file mode 100644 (file)
index 0000000..3a36ff5
--- /dev/null
@@ -0,0 +1,168 @@
+<?php
+/**
+ * A Cipher based MAC generator (Based upon the CMAC specification)
+ *
+ * PHP version 5.3
+ *
+ * @see        http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\MAC\Implementation;
+
+use \CryptLib\Cipher\Factory;
+
+/**
+ * A Cipher based MAC generator (Based upon the CMAC specification)
+ *
+ * @see        http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @subpackage Implementation
+ */
+class CMAC extends \CryptLib\MAC\AbstractMAC {
+
+    protected $cipher = null;
+
+    /**
+     * @var array The stored options for this instance
+     */
+    protected $options = array(
+        'cipher'        => 'aes-128',
+        'cipherFactory' => null,
+    );
+
+    /**
+     * Build the instance of the MAC generator
+     *
+     * @param array $options The options for the instance
+     *
+     * @return void
+     */
+    public function __construct(array $options = array()) {
+        parent::__construct($options);
+        if (is_null($this->options['cipherFactory'])) {
+            $this->options['cipherFactory'] = new Factory;
+        }
+        $this->cipher = $this->options['cipherFactory']->getBlockCipher(
+            $this->options['cipher']
+        );
+    }
+
+    /**
+     * Generate the MAC using the supplied data
+     *
+     * @param string $data The data to use to generate the MAC with
+     * @param string $key  The key to generate the MAC
+     * @param int    $size The size of the output to return
+     *
+     * @return string The generated MAC of the appropriate size
+     */
+    public function generate($data, $key, $size = 0) {
+        $blockSize = $this->cipher->getBlockSize();
+        if ($size == 0) {
+            $size = $blockSize;
+        }
+        if ($size > $blockSize) {
+            throw new \OutOfRangeException(
+                sprintf(
+                    'The size is too big for the cipher primitive [%d:%d]',
+                    $size,
+                    $blockSize
+                )
+            );
+        }
+        $this->cipher->setKey($key);
+        $keys    = $this->generateKeys();
+        $mBlocks = $this->splitDataIntoMBlocks($data, $keys);
+        $cBlock  = str_repeat(chr(0), $blockSize);
+        foreach ($mBlocks as $key => $block) {
+            $cBlock = $this->cipher->encryptBlock($cBlock ^ $block);
+        }
+        return substr($cBlock, 0, $size);
+    }
+
+    /**
+     * Generate a pair of keys by encrypting a block of all 0's, and then
+     * maniuplating the result
+     *
+     * @return array The generated keys
+     */
+    protected function generateKeys() {
+        $keys      = array();
+        $blockSize = $this->cipher->getBlockSize();
+        $rVal      = $this->getRValue($blockSize);
+        $text      = str_repeat(chr(0), $blockSize);
+        $lVal      = $this->cipher->encryptBlock($text);
+        $keys[0]   = $this->leftShift($lVal, 1);
+        if (ord(substr($lVal, 0, 1)) > 127) {
+            $keys[0] = $keys[0] ^ $rVal;
+        }
+        $keys[1] = $this->leftShift($keys[0], 1);
+        if (ord(substr($keys[0], 0, 1)) > 127) {
+            $keys[1] = $keys[1] ^ $rVal;
+        }
+        return $keys;
+    }
+
+    /**
+     * Get an RValue based upon the block size
+     *
+     * @param int $size The size of the block in bytes
+     *
+     * @see http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf
+     * @return string A RValue of the appropriate block size
+     */
+    protected function getRValue($size) {
+        switch ($size * 8) {
+            case 64:
+                return str_repeat(chr(0), 7) . chr(0x1B);
+            case 128:
+                return str_repeat(chr(0), 15) . chr(0x87);
+            default:
+        }
+        throw new \RuntimeException('Unsupported Block Size For The Cipher');
+    }
+
+    protected function leftShift($data, $bits) {
+        $mask   = (0xff << (8 - $bits)) & 0xff;
+        $state  = 0;
+        $result = '';
+        $length = strlen($data);
+        for ($i = $length - 1; $i >= 0; $i--) {
+            $tmp     = ord($data[$i]);
+            $result .= chr(($tmp << $bits) | $state);
+            $state   = ($tmp & $mask) >> (8 - $bits);
+        }
+        return strrev($result);
+    }
+
+    /**
+     * Split the data into appropriate block chunks, encoding with the kyes
+     *
+     * @param string $data The data to split
+     * @param array  $keys The keys to use for encoding
+     *
+     * @return array The array of chunked and encoded data
+     */
+    protected function splitDataIntoMBlocks($data, array $keys) {
+        $blockSize = $this->cipher->getBlockSize();
+        $data      = str_split($data, $blockSize);
+        $last      = end($data);
+        if (strlen($last) != $blockSize) {
+            //Pad the last element
+            $last .= chr(0x80) . str_repeat(chr(0), $blockSize - 1 - strlen($last));
+            $last  = $last ^ $keys[1];
+        } else {
+            $last = $last ^ $keys[0];
+        }
+        $data[count($data) - 1] = $last;
+        return $data;
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/MAC/Implementation/HMAC.php b/CryptLib/MAC/Implementation/HMAC.php
new file mode 100644 (file)
index 0000000..475983c
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+/**
+ * A Hash-Base MAC generator
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\MAC\Implementation;
+
+use \CryptLib\Hash\Hash;
+
+/**
+ * A Hash-Base MAC generator
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @subpackage Implementation
+ */
+class HMAC extends \CryptLib\MAC\AbstractMAC {
+
+    /**
+     * @var array The stored options for this instance
+     */
+    protected $options = array(
+        'hash' => 'sha256',
+    );
+
+    /**
+     * Generate the MAC using the supplied data
+     *
+     * @param string $data The data to use to generate the MAC with
+     * @param string $key  The key to generate the MAC
+     * @param int    $size The size of the output to return
+     *
+     * @return string The generated MAC of the appropriate size
+     */
+    public function generate($data, $key, $size = 0) {
+        $hash       = $this->options['hash'];
+        $outputSize = Hash::getHashSize($hash);
+        if ($size == 0) {
+            $size = $outputSize;
+        }
+        if ($size > $outputSize) {
+            throw new \OutOfRangeException(
+                sprintf(
+                    'The size is too big for the hash primitive [%d:%d]',
+                    $size,
+                    $outputSize
+                )
+            );
+        }
+        $return = hash_hmac($hash, $data, $key, true);
+        return substr($return, 0, $size);
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/MAC/MAC.php b/CryptLib/MAC/MAC.php
new file mode 100644 (file)
index 0000000..eb6d857
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * The basic interface for MAC (Message Authentication Code) generation
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+namespace CryptLib\MAC;
+
+/**
+ * The basic interface for MAC (Message Authentication Code) generation
+ *
+ * @category   PHPCryptLib
+ * @package    MAC
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+interface MAC {
+
+    /**
+     * Build the instance of the MAC generator
+     *
+     * @param array $options The options for the instance
+     *
+     * @return void
+     */
+    public function __construct(array $options = array());
+
+    /**
+     * Generate the MAC using the supplied data
+     *
+     * @param string $data The data to use to generate the MAC with
+     * @param string $key  The key to generate the MAC
+     * @param int    $size The size of the output to return
+     *
+     * @return string The generated MAC of the appropriate size
+     */
+    public function generate($data, $key, $size = 0);
+
+}
diff --git a/CryptLib/Password/Factory.php b/CryptLib/Password/Factory.php
new file mode 100644 (file)
index 0000000..af3b5a0
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+/**
+ * The Password Factory
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password;
+
+use CryptLib\Password\Implementation\Blowfish;
+
+/**
+ * The Password Factory
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Factory extends \CryptLib\Core\AbstractFactory {
+
+    /**
+     * @var array An array of implementation classes
+     */
+    protected $implementations = array();
+
+    /**
+     * Build a new instance of the factory, loading core implementations
+     *
+     * @return void
+     */
+    public function __construct() {
+        $this->loadImplementations();
+    }
+
+    /**
+     * Create a new password hash from the supplied password
+     *
+     * This defaults to using Blowfish if $prefix is not supplied
+     *
+     * @param string $password The password to hash
+     * @param string $prefix   The prefix for the implementation
+     *
+     * @return string The hashed password
+     * @throws DomainException if the supplied prefix is not supported
+     */
+    public function createHash($password, $prefix = '$2a$') {
+        if ($prefix === false) {
+            throw new \DomainException('Unsupported Prefix Supplied');
+        }
+        foreach ($this->implementations as $impl) {
+            if ($impl::getPrefix() == $prefix) {
+                $instance = new $impl;
+                return $instance->create($password);
+            }
+        }
+        throw new \DomainException('Unsupported Prefix Supplied');
+    }
+
+    /**
+     * Verify a hash with a supplied password
+     *
+     * @param string $password The password to check against
+     * @param string $hash     The hash to verify
+     *
+     * @return boolean True if valid, false if not
+     * @throws DomainException if the supplied prefix is not supported
+     */
+    public function verifyHash($password, $hash) {
+        foreach ($this->implementations as $impl) {
+            if ($impl::detect($hash)) {
+                $instance = $impl::loadFromHash($hash);
+                return $instance->verify($password, $hash);
+            }
+        }
+        throw new \DomainException('Unsupported Password Hash Supplied');
+    }
+
+    /**
+     * Register a password implementation for this factory instance
+     *
+     * @param string $name  The name of the stategy
+     * @param string $class The class name of the implementation
+     *
+     * @return Factory $this The current factory instance
+     */
+    public function registerImplementation($name, $class) {
+        $this->registerType(
+            'implementations',
+            __NAMESPACE__ . '\\Password',
+            $name,
+            $class
+        );
+        return $this;
+    }
+
+    /**
+     * Load all core password hashing implementations
+     *
+     * @return void
+     */
+    protected function loadImplementations() {
+        $this->loadFiles(
+            __DIR__ . '/Implementation',
+            __NAMESPACE__ . '\\Implementation\\',
+            array($this, 'registerImplementation')
+        );
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Password/Implementation/APR1.php b/CryptLib/Password/Implementation/APR1.php
new file mode 100644 (file)
index 0000000..c0a4ac0
--- /dev/null
@@ -0,0 +1,224 @@
+<?php
+/**
+ * The APR1 password hashing implementation
+ *
+ * Use this class to generate and validate APR1 password hashes.  APR1 hashes
+ * are used primarrily by Apache for .htaccess password storage.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The APR1 password hashing implementation
+ *
+ * Use this class to generate and validate APR1 password hashes.  APR1 hashes
+ * are used primarrily by Apache for .htaccess password storage.
+ *
+ * @see        http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class APR1 implements \CryptLib\Password\Password {
+
+    /**
+     * @var Generator The random generator to use for seeds
+     */
+    protected $generator = null;
+
+    /**
+     * @var Hash The hash function to use (MD5)
+     */
+    protected $hash = null;
+
+    /**
+     * @var int The number of iterations to perform (1000 for APR1)
+     */
+    protected $iterations = 1000;
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        return strncmp($hash, '$apr1$', 6) === 0;
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        return '$apr1$';
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        return new static;
+    }
+
+    /**
+     * Build a new instance
+     *
+     * @param Generator $generator The random generator to use for seeds
+     *
+     * @return void
+     */
+    public function __construct(
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        if (is_null($generator)) {
+            $random    = new RandomFactory();
+            $generator = $random->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        $salt = $this->to64($this->generator->generateInt(0, PHP_INT_MAX), 8);
+        return $this->hash($password, $salt, $this->iterations);
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        $bits = explode('$', $hash);
+        if (!isset($bits[3]) || $bits[1] != 'apr1') {
+            return false;
+        }
+        $test = $this->hash($password, $bits[2], $this->iterations);
+        return $test == $hash;
+    }
+
+    /**
+     * Perform the hashing of the password
+     *
+     * @param string $password   The plain text password to hash
+     * @param string $salt       The 8 byte salt to use
+     * @param int    $iterations The number of iterations to use
+     *
+     * @return string The hashed password
+     */
+    protected function hash($password, $salt, $iterations) {
+        $len  = strlen($password);
+        $text = $password . '$apr1$' . $salt;
+        $bin  = md5($password.$salt.$password, true);
+        for ($i = $len; $i > 0; $i -= 16) {
+            $text .= substr($bin, 0, min(16, $i));
+        }
+        for ($i = $len; $i > 0; $i >>= 1) {
+            $text .= ($i & 1) ? chr(0) : $password[0];
+        }
+        $bin = $this->iterate($text, $iterations, $salt, $password);
+        return $this->convertToHash($bin, $salt);
+    }
+
+    protected function iterate($text, $iterations, $salt, $password) {
+        $bin = md5($text, true);
+        for ($i = 0; $i < $iterations; $i++) {
+            $new = ($i & 1) ? $password : $bin;
+            if ($i % 3) {
+                $new .= $salt;
+            }
+            if ($i % 7) {
+                $new .= $password;
+            }
+            $new .= ($i & 1) ? $bin : $password;
+            $bin  = md5($new, true);
+        }
+        return $bin;
+    }
+
+    protected function convertToHash($bin, $salt) {
+        $tmp  = '$apr1$'.$salt.'$';
+        $tmp .= $this->to64(
+            (ord($bin[0])<<16) | (ord($bin[6])<<8) | ord($bin[12]),
+            4
+        );
+        $tmp .= $this->to64(
+            (ord($bin[1])<<16) | (ord($bin[7])<<8) | ord($bin[13]),
+            4
+        );
+        $tmp .= $this->to64(
+            (ord($bin[2])<<16) | (ord($bin[8])<<8) | ord($bin[14]),
+            4
+        );
+        $tmp .= $this->to64(
+            (ord($bin[3])<<16) | (ord($bin[9])<<8) | ord($bin[15]),
+            4
+        );
+        $tmp .= $this->to64(
+            (ord($bin[4])<<16) | (ord($bin[10])<<8) | ord($bin[5]),
+            4
+        );
+        $tmp .= $this->to64(
+            ord($bin[11]),
+            2
+        );
+        return $tmp;
+    }
+
+    /**
+     * Convert the input number to a base64 number of the specified size
+     *
+     * @param int $num  The number to convert
+     * @param int $size The size of the result string
+     *
+     * @return string The converted representation
+     */
+    protected function to64($num, $size) {
+        static $seed = '';
+        if (empty($seed)) {
+            $seed = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
+                    'abcdefghijklmnopqrstuvwxyz';
+        }
+        $result = '';
+        while (--$size >= 0) {
+            $result .= $seed[$num & 0x3f];
+            $num   >>= 6;
+        }
+        return $result;
+    }
+
+}
diff --git a/CryptLib/Password/Implementation/Blowfish.php b/CryptLib/Password/Implementation/Blowfish.php
new file mode 100644 (file)
index 0000000..2205286
--- /dev/null
@@ -0,0 +1,195 @@
+<?php
+/**
+ * The Blowfish password hashing implementation
+ *
+ * Use this class to generate and validate Blowfish password hashes.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The Blowfish password hashing implementation
+ *
+ * Use this class to generate and validate Blowfish password hashes.
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Blowfish implements \CryptLib\Password\Password {
+
+    /**
+     * @var Generator The random generator to use for seeds
+     */
+    protected $generator = null;
+
+    /**
+     * @var int The number of iterations to perform (base 2)
+     */
+    protected $iterations = 10;
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        static $regex = '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/';
+        return 1 == preg_match($regex, $hash);
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        if (version_compare(PHP_VERSION, '5.3.7') >= 0) {
+            return '$2y$';
+        } else {
+            return '$2a$';
+        }
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        list(, , $iterations) = explode('$', $hash, 4);
+        return new static((int) $iterations);
+    }
+
+    /**
+     * Build a new instance
+     *
+     * @param int       $iterations The number of times to iterate the hash
+     * @param Generator $generator  The random generator to use for seeds
+     *
+     * @return void
+     */
+    public function __construct(
+        $iterations = 8,
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        if ($iterations > 31 || $iterations < 4) {
+            throw new \InvalidArgumentException('Invalid Iteration Count Supplied');
+        }
+        $this->iterations = $iterations;
+        if (is_null($generator)) {
+            $random    = new RandomFactory();
+            $generator = $random->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        /**
+         * Check for security flaw in the bcrypt implementation used by crypt()
+         * @see http://php.net/security/crypt_blowfish.php
+         */
+        $match = preg_match('/[\x80-\xFF]/', $password);
+        if (version_compare(PHP_VERSION, '5.3.7', '<') && $match) {
+            throw new \RuntimeException(
+                'The bcrypt implementation used by PHP contains a security flaw ' .
+                'for password with 8-bit character. We suggest to upgrade to ' .
+                'PHP 5.3.7+ or use passwords with only 7-bit characters'
+            );
+        }
+        $salt       = $this->to64($this->generator->generate(16));
+        $prefix     = static::getPrefix();
+        $prefix    .= str_pad($this->iterations, 2, '0', STR_PAD_LEFT);
+        $saltstring = $prefix . '$' . $salt;
+        $result     = crypt($password, $saltstring);
+        if ($result[0] == '*') {
+            //@codeCoverageIgnoreStart
+            throw new \RuntimeException('Password Could Not Be Created');
+            //@codeCoverageIgnoreEnd
+        }
+        return $result;
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException(
+                'The hash was not created here, we cannot verify it'
+            );
+        }
+        $test = crypt($password, $hash);
+        return $test == $hash;
+    }
+
+    /**
+     * Convert the input number to a base64 number of the specified size
+     *
+     * @param int $input The number to convert
+     *
+     * @return string The converted representation
+     */
+    protected function to64($input) {
+        static $itoa = null;
+        if (empty($itoa)) {
+            $itoa = './ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+                    . 'abcdefghijklmnopqrstuvwxyz0123456789';
+        }
+        $output = '';
+        $size   = strlen($input);
+        $ictr   = 0;
+        do {
+            $cval1   = ord($input[$ictr++]);
+            $output .= $itoa[$cval1 >> 2];
+            $cval1   = ($cval1 & 0x03) << 4;
+            if ($ictr >= $size) {
+                $output .= $itoa[$cval1];
+                break;
+            }
+            $cval2 = ord($input[$ictr++]);
+            $cval1 |= $cval2 >> 4;
+            $output .= $itoa[$cval1];
+            $cval1   = ($cval2 & 0x0f) << 2;
+            $cval2   = ord($input[$ictr++]);
+            $cval1 |= $cval2 >> 6;
+            $output .= $itoa[$cval1];
+            $output .= $itoa[$cval2 & 0x3f];
+        } while (true);
+        return $output;
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Password/Implementation/Drupal.php b/CryptLib/Password/Implementation/Drupal.php
new file mode 100644 (file)
index 0000000..98ef34c
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * The Drupal password hashing implementation
+ *
+ * Use this class to generate and validate Drupal password hashes.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The PHPASS password hashing implementation
+ *
+ * Use this class to generate and validate PHPASS password hashes.
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Drupal extends PHPASS {
+
+    /**
+     * @var string The prefix for the generated hash
+     */
+    protected static $prefix = '$S$';
+
+    /**
+     * @var string The hash function to use for this instance
+     */
+    protected $hashFunction = 'sha512';
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        $prefix = preg_quote(static::$prefix, '/');
+        return 1 == preg_match('/^'.$prefix.'[a-zA-Z0-9.\/]{95}$/', $hash);
+    }
+
+}
\ No newline at end of file
diff --git a/CryptLib/Password/Implementation/Hash.php b/CryptLib/Password/Implementation/Hash.php
new file mode 100644 (file)
index 0000000..b85b00c
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+/**
+ * The basic Hash implementation.
+ *
+ * It's worth noting, since there's no prefix, you cannot create a hash using
+ * the factory method.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The basic Hash implementation.
+ *
+ * It's worth noting, since there's no prefix, you cannot create a hash using
+ * the factory method.
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Hash implements \CryptLib\Password\Password {
+
+    /**
+     * @var Generator The random generator to use for seeds
+     */
+    protected $generator = null;
+
+    /**
+     * @var Hash The hash function to use (MD5)
+     */
+    protected $hash = null;
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        $res  = preg_match('/^[a-fA-F0-9]+$/', $hash);
+        $res &= (int) in_array(strlen($hash), array(32, 40, 64, 128));
+        return (boolean) $res;
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        return false;
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        $hashMethod = '';
+        switch (strlen($hash)) {
+            case 32:
+                $hashMethod = 'md5';
+                break;
+            case 40:
+                $hashMethod = 'sha1';
+                break;
+            case 64:
+                $hashMethod = 'sha256';
+                break;
+            case 128:
+                $hashMethod = 'sha512';
+                break;
+        }
+        return new static($hashMethod);
+    }
+
+    /**
+     * Build a new instance
+     *
+     * @param string    $hashMethod The hash function to use for hashing
+     * @param Generator $generator  The random generator to use for seeds
+     * @param Factory   $factory    The hash factory to use for this instance
+     *
+     * @return void
+     */
+    public function __construct(
+        $hashMethod,
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        $this->hash = $hashMethod;
+        if (is_null($generator)) {
+            $random    = new RandomFactory();
+            $generator = $random->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        throw new \BadMethodCallException(
+            'Unsalted Passwords are only implemented for verification'
+        );
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        $test = hash($this->hash, $password);
+        return $test == $hash;
+    }
+
+}
diff --git a/CryptLib/Password/Implementation/Joomla.php b/CryptLib/Password/Implementation/Joomla.php
new file mode 100644 (file)
index 0000000..62f7ad3
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+/**
+ * The Joomla based hash implementation based off of the md5-hex hash method
+ *
+ * It's worth noting, since there's no prefix, you cannot create a hash using
+ * the factory method.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The Joomla based hash implementation based off of the md5-hex hash method
+ *
+ * It's worth noting, since there's no prefix, you cannot create a hash using
+ * the factory method.
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Joomla implements \CryptLib\Password\Password {
+
+    /**
+     * @var Generator The random generator to use for seeds
+     */
+    protected $generator = null;
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        return (boolean) preg_match('/^[a-fA-F0-9]{32}:[a-zA-z0-9]{32}$/', $hash);
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        return false;
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        return new static();
+    }
+
+    /**
+     * Build a new instance
+     *
+     * @param Generator $generator  The random generator to use for seeds
+     * @param Factory   $factory    The hash factory to use for this instance
+     *
+     * @return void
+     */
+    public function __construct(
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        if (is_null($generator)) {
+            $random    = new RandomFactory();
+            $generator = $random->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+        $salt  = $this->generator->generateString(32, $chars);
+        $hash  = md5($password . $salt);
+        return $hash . ':' . $salt;
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException(
+                'The hash was not created here, we cannot verify it'
+            );
+        }
+        list ($hash, $salt) = explode(':', $hash, 2);
+        $test               = md5($password . $salt);
+        return $test == $hash;
+    }
+
+}
diff --git a/CryptLib/Password/Implementation/PBKDF.php b/CryptLib/Password/Implementation/PBKDF.php
new file mode 100644 (file)
index 0000000..577053c
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+/**
+ * The PBKDF based password hashing implementation
+ *
+ * Use this class to generate and validate PBKDF hashed passwords.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Key\Factory                 as KeyFactory;
+use CryptLib\Random\Factory              as RandomFactory;
+use CryptLib\Key\Derivation\PBKDF\PBKDF2 as PBKDF2;
+
+/**
+ * The PBKDF based password hashing implementation
+ *
+ * Use this class to generate and validate PBKDF hashed passwords.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PBKDF implements \CryptLib\Password\Password {
+
+    /**
+     * @var PBKDF The PBKDF derivation implementation to use for this instance
+     */
+    protected $derivation = null;
+
+    /**
+     * @var Generator The Random Number Generator to use for making salts
+     */
+    protected $generator = null;
+
+    /**
+     * @var int The number of iterations to perform on the password
+     */
+    protected $iterations = 5000;
+
+    /**
+     * @var int The length in bytes of the generated password hash
+     */
+    protected $size = 40;
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        return strncmp($hash, '$pbkdf$', 7) === 0;
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        return '$pbkdf$';
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        $parts = explode('$', $hash);
+        if (count($parts) != 7) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        $signature  = $parts[2];
+        $factory    = new KeyFactory();
+        $hash       = $factory->getPBKDFFromSignature($signature);
+        $iterations = $parts[3];
+        $size       = $parts[4];
+        return new static($hash, $size, $iterations);
+    }
+
+    /**
+     * Build a new instance of the PBKDF password class
+     *
+     * @param PBKDF     $derivation The derivation class to use
+     * @param int       $size       The size of hash to generate
+     * @param int       $iterations The number of iterations to perform
+     * @param Generator $generator  The Random Generator to use
+     *
+     * @return void;
+     */
+    public function __construct(
+        \CryptLib\Key\Derivation\PBKDF $derivation = null,
+        $size = 40,
+        $iterations = 5000,
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        if (is_null($derivation)) {
+            $derivation = new PBKDF2();
+        }
+        $this->derivation = $derivation;
+        $this->size       = $size < 40 ? 40 : (int) $size;
+        $this->iterations = $iterations > 0 ? (int) $iterations : 1;
+        if (is_null($generator)) {
+            $factory   = new RandomFactory;
+            $generator = $factory->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        $size     = $this->size - 8; // remove size of stored bits
+        $saltSize = floor($size / 5);  //Use 20% of the size for the salt
+        $hashSize = $size - $saltSize;
+        $salt     = $this->generator->generate($saltSize);
+        return $this->hash($password, $salt, $this->iterations, $hashSize);
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        if (strlen($hash) <= 16 || strpos($hash, '$') === false) {
+            return false;
+        }
+        $parts = explode('$', $hash);
+        if (count($parts) != 7) {
+            return false;
+        } elseif ($parts[2] != $this->derivation->getSignature()) {
+            return false;
+        }
+        $iterations = $parts[3];
+        $size       = $parts[4];
+        $salt       = base64_decode($parts[5]);
+        return $this->hash($password, $salt, $iterations, $size) == $hash;
+    }
+
+    /**
+     * Perform the hashing of the password
+     *
+     * @param string $password   The plain text password to hash
+     * @param string $salt       The 8 byte salt to use
+     * @param int    $iterations The number of iterations to use
+     *
+     * @return string The hashed password
+     */
+    protected function hash($password, $salt, $iterations, $size) {
+        $bit = $this->derivation->derive($password, $salt, $iterations, $size);
+        $sig = $this->derivation->getSignature();
+        $sig = '$pbkdf$' . $sig . '$' . $iterations . '$' . $size;
+        return $sig . '$' . base64_encode($salt) . '$' . base64_encode($bit);
+    }
+
+}
diff --git a/CryptLib/Password/Implementation/PHPASS.php b/CryptLib/Password/Implementation/PHPASS.php
new file mode 100644 (file)
index 0000000..4522e87
--- /dev/null
@@ -0,0 +1,246 @@
+<?php
+/**
+ * The PHPASS password hashing implementation
+ *
+ * Use this class to generate and validate PHPASS password hashes.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The PHPASS password hashing implementation
+ *
+ * Use this class to generate and validate PHPASS password hashes.
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PHPASS implements \CryptLib\Password\Password {
+
+    /**
+     * @var string The ITOA string to be used for base64 conversion
+     */
+    protected static $itoa = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
+                                abcdefghijklmnopqrstuvwxyz';
+
+    /**
+     * @var Generator The random generator to use for seeds
+     */
+    protected $generator = null;
+
+    /**
+     * This is the hash function to use.  To be overriden by child classes
+     *
+     * @var string The hash function to use for this instance
+     */
+    protected $hashFunction = 'md5';
+
+    /**
+     * @var int The number of iterations to perform (base 2)
+     */
+    protected $iterations = 10;
+
+    /**
+     * @var string The prefix for the generated hash
+     */
+    protected static $prefix = '$P$';
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash) {
+        $prefix = preg_quote(static::$prefix, '/');
+        return 1 == preg_match('/^'.$prefix.'[a-zA-Z0-9.\/]{31}$/', $hash);
+    }
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix() {
+        return static::$prefix;
+    }
+
+    /**
+     * Initialize the password hasher by replacing away spaces in the itoa var
+     *
+     * @return void
+     */
+    public static function init() {
+        static::$itoa = preg_replace('/\s/', '', static::$itoa);
+    }
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     * @throws InvalidArgumentException if the hash wasn't created here
+     */
+    public static function loadFromHash($hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException('Hash Not Created Here');
+        }
+        $iterations = static::decodeIterations($hash[3]);
+        return new static($iterations);
+    }
+
+    /**
+     * Decode an ITOA encoded iteration count
+     *
+     * @param string $byte The character to decode
+     *
+     * @return int The decoded iteration count (base2)
+     */
+    protected static function decodeIterations($byte) {
+        return strpos(static::$itoa, $byte);
+    }
+
+    /**
+     * Encode a base2 iteration count to a base64 character
+     *
+     * @param int $number
+     *
+     * @return string The encoded character
+     */
+    protected static function encodeIterations($number) {
+        return static::$itoa[$number];
+    }
+
+    /**
+     * Build a new instance
+     *
+     * @param int       $iterations The number of times to iterate the hash
+     * @param Generator $generator  The random generator to use for seeds
+     * @param Factory   $factory    The hash factory to use for this instance
+     *
+     * @return void
+     */
+    public function __construct(
+        $iterations = 8,
+        \CryptLib\Random\Generator $generator = null
+    ) {
+        if ($iterations > 30 || $iterations < 7) {
+            throw new \InvalidArgumentException('Invalid Iteration Count Supplied');
+        }
+        $this->iterations = $iterations;
+        if (is_null($generator)) {
+            $random    = new RandomFactory();
+            $generator = $random->getMediumStrengthGenerator();
+        }
+        $this->generator = $generator;
+    }
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password) {
+        $salt   = $this->to64($this->generator->generate(6));
+        $prefix = static::encodeIterations($this->iterations) . $salt;
+        return static::$prefix . $prefix . $this->hash($password, $salt);
+    }
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash) {
+        if (!static::detect($hash)) {
+            throw new \InvalidArgumentException(
+                'The hash was not created here, we cannot verify it'
+            );
+        }
+        $iterations = static::decodeIterations($hash[3]);
+        if ($iterations != $this->iterations) {
+            throw new \InvalidArgumentException(
+                'Iteration Count Mismatch, Bailing'
+            );
+        }
+        $salt = substr($hash, 4, 8);
+        $hash = substr($hash, 12);
+        $test = $this->hash($password, $salt);
+        return $test == $hash;
+    }
+
+    /**
+     * Execute the hash function with proper iterations
+     *
+     * @param string $password The password to hash
+     * @param string $salt     The salt to use to hash
+     *
+     * @return string The base64 encoded generated hash
+     */
+    protected function hash($password, $salt) {
+        $count = 1 << $this->iterations;
+        $hash  = hash($this->hashFunction, $salt . $password, true);
+        do {
+            $hash = hash($this->hashFunction, $hash . $password, true);
+        } while (--$count);
+        return $this->to64($hash);
+    }
+
+    /**
+     * Convert the input number to a base64 number of the specified size
+     *
+     * @param int $input The number to convert
+     *
+     * @return string The converted representation
+     */
+    protected function to64($input) {
+        $output = '';
+        $count  = strlen($input);
+        $ictr   = 0;
+        do {
+            $value   = ord($input[$ictr++]);
+            $output .= static::$itoa[$value & 0x3f];
+            if ($ictr < $count) {
+                $value |= ord($input[$ictr]) << 8;
+            }
+            $output .= static::$itoa[($value >> 6) & 0x3f];
+            if ($ictr++ >= $count) {
+                break;
+            }
+            if ($ictr < $count) {
+                $value |= ord($input[$ictr]) << 16;
+            }
+            $output .= static::$itoa[($value >> 12) & 0x3f];
+            if ($ictr++ < $count) {
+                $output .= static::$itoa[($value >> 18) & 0x3f];
+            }
+        } while ($ictr < $count);
+        return $output;
+    }
+
+}
+
+PHPASS::init();
\ No newline at end of file
diff --git a/CryptLib/Password/Implementation/PHPBB.php b/CryptLib/Password/Implementation/PHPBB.php
new file mode 100644 (file)
index 0000000..ce108f6
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The PHPBB password hashing implementation
+ *
+ * Use this class to generate and validate PHPBB password hashes.
+ *
+ * PHP version 5.3
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password\Implementation;
+
+use CryptLib\Random\Factory as RandomFactory;
+
+/**
+ * The PHPBB password hashing implementation
+ *
+ * Use this class to generate and validate PHPBB password hashes.
+ *
+ * @see        http://www.openwall.com/phpass/
+ * @category   PHPCryptLib
+ * @package    Password
+ * @subpackage Implementation
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class PHPBB extends PHPASS {
+
+    /**
+     * @var string The prefix for the generated hash
+     */
+    protected static $prefix = '$H$';
+
+}
\ No newline at end of file
diff --git a/CryptLib/Password/Password.php b/CryptLib/Password/Password.php
new file mode 100644 (file)
index 0000000..e2487ce
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/**
+ * The core password hash interface
+ *
+ * All pasword implementations must implement this interface
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Password;
+
+/**
+ * The core password key interface
+ *
+ * All pasword implementations must implement this interface
+ *
+ * @category   PHPCryptLib
+ * @package    Password
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface Password {
+
+    /**
+     * Determine if the hash was made with this method
+     *
+     * @param string $hash The hashed data to check
+     *
+     * @return boolean Was the hash created by this method
+     */
+    public static function detect($hash);
+
+    /**
+     * Return the prefix used by this hashing method
+     *
+     * @return string The prefix used
+     */
+    public static function getPrefix();
+
+    /**
+     * Load an instance of the class based upon the supplied hash
+     *
+     * @param string $hash The hash to load from
+     *
+     * @return Password the created instance
+     */
+    public static function loadFromHash($hash);
+
+    /**
+     * Create a password hash for a given plain text password
+     *
+     * @param string $password The password to hash
+     *
+     * @return string The formatted password hash
+     */
+    public function create($password);
+
+    /**
+     * Verify a password hash against a given plain text password
+     *
+     * @param string $password The password to hash
+     * @param string $hash     The supplied ahsh to validate
+     *
+     * @return boolean Does the password validate against the hash
+     */
+    public function verify($password, $hash);
+
+}
diff --git a/CryptLib/Random/AbstractMixer.php b/CryptLib/Random/AbstractMixer.php
new file mode 100644 (file)
index 0000000..6864058
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+/**
+ * An abstract mixer to implement a common mixing strategy
+ *
+ * PHP version 5.3
+ *
+ * @category  PHPCryptLib
+ * @package   Random
+ * @author    Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright 2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version   Build @@version@@
+ */
+
+namespace CryptLib\Random;
+
+/**
+ * An abstract mixer to implement a common mixing strategy
+ *
+ * @see      http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category PHPCryptLib
+ * @package  Random
+ * @author   Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+abstract class AbstractMixer implements \CryptLib\Random\Mixer {
+
+    /**
+     * Get the block size (the size of the individual blocks used for the mixing)
+     * 
+     * @return int The block size
+     */
+    abstract protected function getPartSize();
+
+    /**
+     * Mix 2 parts together using one method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     * 
+     * @return string The mixed data
+     */
+    abstract protected function mixParts1($part1, $part2);
+
+    /**
+     * Mix 2 parts together using another different method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     * 
+     * @return string The mixed data
+     */
+    abstract protected function mixParts2($part1, $part2);
+
+    /**
+     * Mix the provided array of strings into a single output of the same size
+     *
+     * All elements of the array should be the same size.
+     *
+     * @param array $parts The parts to be mixed
+     *
+     * @return string The mixed result
+     */
+    public function mix(array $parts) {
+        if (empty($parts)) {
+            return '';
+        }
+        $len        = strlen($parts[0]);
+        $parts      = $this->normalizeParts($parts);
+        $stringSize = count($parts[0]);
+        $partsSize  = count($parts);
+        $result     = '';
+        $offset     = 0;
+        for ($i = 0; $i < $stringSize; $i++) {
+            $stub = $parts[$offset][$i];
+            for ($j = 1; $j < $partsSize; $j++) {
+                $newKey = $parts[($j + $offset) % $partsSize][$i];
+                //Alternately mix the output for each source
+                if ($j % 2 == 1) {
+                    $stub ^= $this->mixParts1($stub, $newKey);
+                } else {
+                    $stub ^= $this->mixParts2($stub, $newKey);
+                }
+            }
+            $result .= $stub;
+            $offset  = ($offset + 1) % $partsSize;
+        }
+        return substr($result, 0, $len);
+    }
+
+    /**
+     * Normalize the part array and split it block part size.  
+     * 
+     * This will make all parts the same length and a multiple
+     * of the part size
+     *
+     * @param array $parts The parts to normalize
+     * 
+     * @return array The normalized and split parts
+     */
+    protected function normalizeParts(array $parts) {
+        $blockSize = $this->getPartSize();
+        $callback  = function($value) {
+            return strlen($value);
+        };
+        $maxSize = max(array_map($callback, $parts));
+        if ($maxSize % $blockSize != 0) {
+            $maxSize += $blockSize - ($maxSize % $blockSize);
+        }
+        foreach ($parts as &$part) {
+            $part = str_pad($part, $maxSize, chr(0));
+            $part = str_split($part, $blockSize);
+        }
+        return $parts;
+    }
+}
diff --git a/CryptLib/Random/Factory.php b/CryptLib/Random/Factory.php
new file mode 100644 (file)
index 0000000..468624a
--- /dev/null
@@ -0,0 +1,221 @@
+<?php
+/**
+ * The Random Factory
+ *
+ * Use this factory to instantiate random number generators, sources and mixers.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random;
+
+use CryptLib\Core\Strength;
+
+/**
+ * The Random Factory
+ *
+ * Use this factory to instantiate random number generators, sources and mixers.
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Factory extends \CryptLib\Core\AbstractFactory {
+
+    /**
+     * @var array A list of available random number mixing strategies
+     */
+    protected $mixers = array();
+
+    /**
+     * @var array A list of available random number sources
+     */
+    protected $sources = array();
+
+    /**
+     * Build a new instance of the factory, loading core mixers and sources
+     *
+     * @return void
+     */
+    public function __construct() {
+        $this->loadMixers();
+        $this->loadSources();
+    }
+
+    /**
+     * Get a generator for the requested strength
+     *
+     * @param Strength $strength The requested strength of the random number
+     *
+     * @return Generator The instantiated generator
+     * @throws RuntimeException If an appropriate mixing strategy isn't found
+     */
+    public function getGenerator(\CryptLib\Core\Strength $strength) {
+        $sources    = $this->getSources();
+        $newSources = array();
+        foreach ($sources as $source) {
+            if ($strength->compare($source::getStrength()) <= 0) {
+                $newSources[] = new $source;
+            }
+        }
+        $mixer = $this->findMixer($strength);
+        return new Generator($newSources, $mixer);
+    }
+
+    /**
+     * Get a high strength random number generator
+     *
+     * High Strength keys should ONLY be used for generating extremely strong
+     * cryptographic keys.  Generating them is very resource intensive and may
+     * take several minutes or more depending on the requested size.
+     *
+     * @return Generator The instantiated generator
+     */
+    public function getHighStrengthGenerator() {
+        return $this->getGenerator(new Strength(Strength::HIGH));
+    }
+
+    /**
+     * Get a low strength random number generator
+     *
+     * Low Strength should be used anywhere that random strings are needed in a
+     * non-cryptographical setting.  They are not strong enough to be used as
+     * keys or salts.  They are however useful for one-time use tokens.
+     *
+     * @return Generator The instantiated generator
+     */
+    public function getLowStrengthGenerator() {
+        return $this->getGenerator(new Strength(Strength::LOW));
+    }
+
+    /**
+     * Get a medium strength random number generator
+     *
+     * Medium Strength should be used for most needs of a cryptographic nature.
+     * They are strong enough to be used as keys and salts.  However, they do
+     * take some time and resources to generate, so they should not be over-used
+     *
+     * @return Generator The instantiated generator
+     */
+    public function getMediumStrengthGenerator() {
+        return $this->getGenerator(new Strength(Strength::MEDIUM));
+    }
+
+    /**
+     * Get all loaded mixing strategies
+     *
+     * @return array An array of mixers
+     */
+    public function getMixers() {
+        return $this->mixers;
+    }
+
+    /**
+     * Get all loaded random number sources
+     *
+     * @return array An array of sources
+     */
+    public function getSources() {
+        return $this->sources;
+    }
+
+    /**
+     * Register a mixing strategy for this factory instance
+     *
+     * @param string $name  The name of the stategy
+     * @param string $class The class name of the implementation
+     *
+     * @return Factory $this The current factory instance
+     */
+    public function registerMixer($name, $class) {
+        $this->registerType(
+            'mixers',
+            __NAMESPACE__ . '\\Mixer',
+            $name,
+            $class
+        );
+        return $this;
+    }
+
+    /**
+     * Register a random number source for this factory instance
+     *
+     * Note that this class must implement the Source interface
+     *
+     * @param string $name  The name of the stategy
+     * @param string $class The class name of the implementation
+     *
+     * @return Factory $this The current factory instance
+     */
+    public function registerSource($name, $class) {
+        $this->registerType(
+            'sources',
+            __NAMESPACE__ . '\\Source',
+            $name,
+            $class
+        );
+        return $this;
+    }
+
+    /**
+     * Find a mixer based upon the requested strength
+     *
+     * @param Strength $strength The strength mixer to find
+     *
+     * @return Mixer The found mixer
+     * @throws RuntimeException if a valid mixer cannot be found
+     */
+    protected function findMixer(\CryptLib\Core\Strength $strength) {
+        $newMixer = null;
+        $fallback = null;
+        foreach ($this->getMixers() as $mixer) {
+            if ($strength->compare($mixer::getStrength()) == 0) {
+                $newMixer = new $mixer;
+            } elseif ($strength->compare($mixer::getStrength()) == 1) {
+                $fallback = new $mixer;
+            }
+        }
+        if (is_null($newMixer)) {
+            if (is_null($fallback)) {
+                throw new \RuntimeException('Could not find mixer');
+            }
+            return $fallback;
+        }
+        return $newMixer;
+    }
+
+    /**
+     * Load all core mixing strategies
+     *
+     * @return void
+     */
+    protected function loadMixers() {
+        $this->loadFiles(
+            __DIR__ . '/Mixer',
+            __NAMESPACE__ . '\\Mixer\\',
+            array($this, 'registerMixer')
+        );
+    }
+
+    /**
+     * Load all core random number sources
+     *
+     * @return void
+     */
+    protected function loadSources() {
+        $this->loadFiles(
+            __DIR__ . '/Source',
+            __NAMESPACE__ . '\\Source\\',
+            array($this, 'registerSource')
+        );
+    }
+
+}
+
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;
+    }
+
+}
diff --git a/CryptLib/Random/Mixer.php b/CryptLib/Random/Mixer.php
new file mode 100644 (file)
index 0000000..7fab222
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * The Mixer strategy interface.
+ *
+ * All mixing strategies must implement this interface
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random;
+
+/**
+ * The Mixer strategy interface.
+ *
+ * All mixing strategies must implement this interface
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface Mixer {
+
+    /**
+     * Return an instance of Strength indicating the strength of the mixer
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength();
+
+    /**
+     * Test to see if the mixer is available
+     *
+     * @return boolean If the mixer is available on the system
+     */
+    public static function test();
+
+    /**
+     * Mix the provided array of strings into a single output of the same size
+     *
+     * All elements of the array should be the same size.
+     *
+     * @param array $parts The parts to be mixed
+     *
+     * @return string The mixed result
+     */
+    public function mix(array $parts);
+
+}
diff --git a/CryptLib/Random/Mixer/DES.php b/CryptLib/Random/Mixer/DES.php
new file mode 100644 (file)
index 0000000..2c4c287
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/**
+ * The DES medium strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * PHP version 5.3
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random\Mixer;
+
+use \CryptLib\Cipher\Factory       as CipherFactory;
+use \CryptLib\Core\Strength;
+
+/**
+ * The DES medium strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class DES extends \CryptLib\Random\AbstractMixer {
+
+    /**
+     * An instance of a DES symmetric encryption cipher
+     *
+     * @var Cipher The DES cipher instance
+     */
+    protected $cipher = 'des';
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength() {
+        return new Strength(Strength::MEDIUM);
+    }
+
+    /**
+     * Test to see if the mixer is available
+     *
+     * @return boolean If the mixer is available on the system
+     */
+    public static function test() {
+        return true;
+    }
+
+    /**
+     * Build a new instance of the DES mixing function
+     *
+     * @param Factory $factory The optional encryption factory to use
+     *
+     * @return void
+     */
+    public function __construct(\CryptLib\Cipher\Factory $factory = null) {
+        if (is_null($factory)) {
+            $factory = new CipherFactory();
+        }
+        $this->cipher = $factory->getBlockCipher($this->cipher);
+    }
+
+    /**
+     * Get the block size (the size of the individual blocks used for the mixing)
+     *
+     * @return int The block size
+     */
+    protected function getPartSize() {
+        return $this->cipher->getBlockSize();
+    }
+
+    /**
+     * Mix 2 parts together using one method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     *
+     * @return string The mixed data
+     */
+    protected function mixParts1($part1, $part2) {
+        $this->cipher->setKey($part2);
+        return $this->cipher->encryptBlock($part1);
+    }
+
+    /**
+     * Mix 2 parts together using another different method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     *
+     * @return string The mixed data
+     */
+    protected function mixParts2($part1, $part2) {
+        $this->cipher->setKey($part1);
+        return $this->cipher->decryptBlock($part2);
+    }
+
+}
diff --git a/CryptLib/Random/Mixer/Hash.php b/CryptLib/Random/Mixer/Hash.php
new file mode 100644 (file)
index 0000000..086d924
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+/**
+ * The Hash medium strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * PHP version 5.3
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random\Mixer;
+
+use \CryptLib\Core\Strength;
+
+/**
+ * The Hash medium strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Hash extends \CryptLib\Random\AbstractMixer {
+
+    /**
+     * @var string The hash instance to use
+     */
+    protected $hash = null;
+
+    /**
+     * Build the hash mixer
+     *
+     * @param string $hash The hash instance to use (defaults to sha512)
+     *
+     * @return void
+     */
+    public function __construct($hash = 'sha512') {
+        $this->hash = $hash;
+    }
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength() {
+        return new Strength(Strength::LOW);
+    }
+
+    /**
+     * Test to see if the mixer is available
+     *
+     * @return boolean If the mixer is available on the system
+     */
+    public static function test() {
+        return true;
+    }
+
+    /**
+     * Get the block size (the size of the individual blocks used for the mixing)
+     *
+     * @return int The block size
+     */
+    protected function getPartSize() {
+        return strlen(hash($this->hash, '', true));
+    }
+
+    /**
+     * Mix 2 parts together using one method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     *
+     * @return string The mixed data
+     */
+    protected function mixParts1($part1, $part2) {
+        return hash_hmac($this->hash, $part1, $part2, true);
+    }
+
+    /**
+     * Mix 2 parts together using another different method
+     *
+     * @param string $part1 The first part to mix
+     * @param string $part2 The second part to mix
+     *
+     * @return string The mixed data
+     */
+    protected function mixParts2($part1, $part2) {
+        return hash_hmac($this->hash, $part2, $part1, true);
+    }
+
+}
diff --git a/CryptLib/Random/Mixer/Rijndael.php b/CryptLib/Random/Mixer/Rijndael.php
new file mode 100644 (file)
index 0000000..7114fbc
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The Rijndael-128 based high strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * PHP version 5.3
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random\Mixer;
+
+use \CryptLib\Cipher\Factory as CipherFactory;
+use \CryptLib\Core\Strength;
+
+/**
+ * The Rijndael-128 based high strength mixer class
+ *
+ * This class implements a mixer based upon the recommendations in RFC 4086
+ * section 5.2
+ *
+ * @see        http://tools.ietf.org/html/rfc4086#section-5.2
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Mixer
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ */
+class Rijndael extends DES {
+
+    /**
+     * An instance of a Rijndael symmetric encryption cipher
+     *
+     * @var Cipher The Rijndael cipher instance
+     */
+    protected $cipher = 'rijndael-128';
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength() {
+        return new Strength(Strength::HIGH);
+    }
+
+}
diff --git a/CryptLib/Random/Source.php b/CryptLib/Random/Source.php
new file mode 100644 (file)
index 0000000..89eaf66
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * The Random Number Source interface.
+ *
+ * All random number sources must implement this interface
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random;
+
+/**
+ * The Random Number Source interface.
+ *
+ * All random number sources must implement this interface
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+interface Source {
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength();
+
+    /**
+     * Generate a random string of the specified size
+     *
+     * Note: If the source fails to generate enough data, the result must be
+     * padded to the requested length.
+     *
+     * @param int $size The size of the requested random string
+     *
+     * @return string A string of the requested size
+     */
+    public function generate($size);
+
+}
diff --git a/CryptLib/Random/Source/CAPICOM.php b/CryptLib/Random/Source/CAPICOM.php
new file mode 100644 (file)
index 0000000..8d6c98d
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+/**
+ * The Capicom Random Number Source
+ *
+ * This uses the Windows CapiCom Com object to generate random numbers
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Source
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random\Source;
+
+use CryptLib\Core\Strength;
+
+/**
+ * The Capicom Random Number Source
+ *
+ * This uses the Windows CapiCom Com object to generate random numbers
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Source
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+class CAPICOM implements \CryptLib\Random\Source {
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength() {
+        return new Strength(Strength::MEDIUM);
+    }
+
+    /**
+     * Generate a random string of the specified size
+     *
+     * @param int $size The size of the requested random string
+     *
+     * @return string A string of the requested size
+     */
+    public function generate($size) {
+        if (!class_exists('\\COM', false)) {
+            return str_repeat(chr(0), $size);
+        }
+        try {
+            $util = new \COM('CAPICOM.Utilities.1');
+            $data = base64_decode($util->GetRandom($size, 0));
+            return str_pad($data, $size, chr(0));
+        } catch (\Exception $e) {
+            unset($e);
+            return str_repeat(chr(0), $size);
+        }
+    }
+
+}
diff --git a/CryptLib/Random/Source/MTRand.php b/CryptLib/Random/Source/MTRand.php
new file mode 100644 (file)
index 0000000..e96cbba
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+/**
+ * The MTRand Random Number Source
+ *
+ * This source generates low strength random numbers by using the internal
+ * mt_rand() function.  By itself it is quite weak.  However when combined with
+ * other sources it does provide significant benefit.
+ *
+ * PHP version 5.3
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Source
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @copyright  2011 The Authors
+ * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
+ * @version    Build @@version@@
+ */
+
+namespace CryptLib\Random\Source;
+
+use CryptLib\Core\Strength;
+
+/**
+ * The MTRand Random Number Source
+ *
+ * This source generates low strength random numbers by using the internal
+ * mt_rand() function.  By itself it is quite weak.  However when combined with
+ * other sources it does provide significant benefit.
+ *
+ * @category   PHPCryptLib
+ * @package    Random
+ * @subpackage Source
+ * @author     Anthony Ferrara <ircmaxell@ircmaxell.com>
+ * @codeCoverageIgnore
+ */
+class MTRand implements \CryptLib\Random\Source {
+
+    /**
+     * Return an instance of Strength indicating the strength of the source
+     *
+     * @return Strength An instance of one of the strength classes
+     */
+    public static function getStrength() {
+        // Detect if Suhosin Hardened PHP patch is applied
+        if (defined('S_ALL')) {
+            return new Strength(Strength::MEDIUM);
+        } else {
+            return new Strength(Strength::LOW);
+        }
+    }
+
+    /**
+     * Generate a random string of the specified size
+     *
+     * @param int $size The size of the requested random string
+     *
+     * @return string A string of the requested size
+     */
+    public function generate($size) {
+        $result = '';
+        for ($i = 0; $i < $size; $i++) {
+            $result .= chr((mt_rand() ^ mt_rand()) % 256);
+        }
+        return $result;
+    }
+
+}