diff options
Diffstat (limited to 'mod/openid_server/Crypt')
| -rw-r--r-- | mod/openid_server/Crypt/RSA.php | 524 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/ErrorHandler.php | 234 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/Key.php | 314 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/KeyPair.php | 804 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/Math/BCMath.php | 482 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/Math/BigInt.php | 313 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/Math/GMP.php | 361 | ||||
| -rw-r--r-- | mod/openid_server/Crypt/RSA/MathLoader.php | 135 | 
8 files changed, 3167 insertions, 0 deletions
diff --git a/mod/openid_server/Crypt/RSA.php b/mod/openid_server/Crypt/RSA.php new file mode 100644 index 000000000..16dfa54d4 --- /dev/null +++ b/mod/openid_server/Crypt/RSA.php @@ -0,0 +1,524 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version    1.2.0b + * @link       http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * helper class for mange single key + */ +require_once 'Crypt/RSA/Key.php'; + +/** + * helper class for manage key pair + */ +require_once 'Crypt/RSA/KeyPair.php'; + +/** + * Crypt_RSA class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + *  - setParams($params) - sets parameters of current object + *  - encrypt($plain_data, $key = null) - encrypts data + *  - decrypt($enc_data, $key = null) - decrypts data + *  - createSign($doc, $private_key = null) - signs document by private key + *  - validateSign($doc, $signature, $public_key = null) - validates signature of document + * + * Example usage: + *     // creating an error handler + *     $error_handler = create_function('$obj', 'echo "error: ", $obj->getMessage(), "\n"'); + * + *     // 1024-bit key pair generation + *     $key_pair = new Crypt_RSA_KeyPair(1024); + * + *     // check consistence of Crypt_RSA_KeyPair object + *     $error_handler($key_pair); + * + *     // creating Crypt_RSA object + *     $rsa_obj = new Crypt_RSA; + * + *     // check consistence of Crypt_RSA object + *     $error_handler($rsa_obj); + * + *     // set error handler on Crypt_RSA object ( see Crypt/RSA/ErrorHandler.php for details ) + *     $rsa_obj->setErrorHandler($error_handler); + * + *     // encryption (usually using public key) + *     $enc_data = $rsa_obj->encrypt($plain_data, $key_pair->getPublicKey()); + * + *     // decryption (usually using private key) + *     $plain_data = $rsa_obj->decrypt($enc_data, $key_pair->getPrivateKey()); + * + *     // signing + *     $signature = $rsa_obj->createSign($document, $key_pair->getPrivateKey()); + * + *     // signature checking + *     $is_valid = $rsa_obj->validateSign($document, $signature, $key_pair->getPublicKey()); + * + *     // signing many documents by one private key + *     $rsa_obj = new Crypt_RSA(array('private_key' => $key_pair->getPrivateKey())); + *     // check consistence of Crypt_RSA object + *     $error_handler($rsa_obj); + *     // set error handler ( see Crypt/RSA/ErrorHandler.php for details ) + *     $rsa_obj->setErrorHandler($error_handler); + *     // sign many documents + *     $sign_1 = $rsa_obj->sign($doc_1); + *     $sign_2 = $rsa_obj->sign($doc_2); + *     //... + *     $sign_n = $rsa_obj->sign($doc_n); + * + *     // changing default hash function, which is used for sign + *     // creating/validation + *     $rsa_obj->setParams(array('hash_func' => 'md5')); + * + *     // using factory() method instead of constructor (it returns PEAR_Error object on failure) + *     $rsa_obj = &Crypt_RSA::factory(); + *     if (PEAR::isError($rsa_obj)) { + *         echo "error: ", $rsa_obj->getMessage(), "\n"; + *     } + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @link       http://pear.php.net/package/Crypt_RSA + * @version    @package_version@ + * @access     public + */ +class Crypt_RSA extends Crypt_RSA_ErrorHandler +{ +    /** +     * Reference to math wrapper, which is used to +     * manipulate large integers in RSA algorithm. +     * +     * @var object of Crypt_RSA_Math_* class +     * @access private +     */ +    var $_math_obj; + +    /** +     * key for encryption, which is used by encrypt() method +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_enc_key; + +    /** +     * key for decryption, which is used by decrypt() method +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_dec_key; + +    /** +     * public key, which is used by validateSign() method +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_public_key; + +    /** +     * private key, which is used by createSign() method +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_private_key; + +    /** +     * name of hash function, which is used by validateSign() +     * and createSign() methods. Default hash function is SHA-1 +     * +     * @var string +     * @access private +     */ +    var $_hash_func = 'sha1'; + +    /** +     * Crypt_RSA constructor. +     * +     * @param array $params +     *        Optional associative array of parameters, such as: +     *        enc_key, dec_key, private_key, public_key, hash_func. +     *        See setParams() method for more detailed description of +     *        these parameters. +     * @param string $wrapper_name +     *        Name of math wrapper, which will be used to +     *        perform different operations with big integers. +     *        See contents of Crypt/RSA/Math folder for examples of wrappers. +     *        Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * @param string $error_handler   name of error handler function +     * +     * @access public +     */ +    function Crypt_RSA($params = null, $wrapper_name = 'default', $error_handler = '') +    { +        // set error handler +        $this->setErrorHandler($error_handler); +        // try to load math wrapper +        $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); +        if ($this->isError($obj)) { +            // error during loading of math wrapper +            // Crypt_RSA object is partially constructed. +            $this->pushError($obj); +            return; +        } +        $this->_math_obj = &$obj; + +        if (!is_null($params)) { +            if (!$this->setParams($params)) { +                // error in Crypt_RSA::setParams() function +                return; +            } +        } +    } + +    /** +     * Crypt_RSA factory. +     * +     * @param array $params +     *        Optional associative array of parameters, such as: +     *        enc_key, dec_key, private_key, public_key, hash_func. +     *        See setParams() method for more detailed description of +     *        these parameters. +     * @param string $wrapper_name +     *        Name of math wrapper, which will be used to +     *        perform different operations with big integers. +     *        See contents of Crypt/RSA/Math folder for examples of wrappers. +     *        Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * @param string $error_handler   name of error handler function +     * +     * @return object  new Crypt_RSA object on success or PEAR_Error object on failure +     * @access public +     */ +    function &factory($params = null, $wrapper_name = 'default', $error_handler = '') +    { +        $obj = &new Crypt_RSA($params, $wrapper_name, $error_handler); +        if ($obj->isError()) { +            // error during creating a new object. Retrurn PEAR_Error object +            return $obj->getLastError(); +        } +        // object created successfully. Return it +        return $obj; +    } + +    /** +     * Accepts any combination of available parameters as associative array: +     *     enc_key - encryption key for encrypt() method +     *     dec_key - decryption key for decrypt() method +     *     public_key - key for validateSign() method +     *     private_key - key for createSign() method +     *     hash_func - name of hash function, which will be used to create and validate sign +     * +     * @param array $params +     *        associative array of permitted parameters (see above) +     * +     * @return bool   true on success or false on error +     * @access public +     */ +    function setParams($params) +    { +        if (!is_array($params)) { +            $this->pushError('parameters must be passed to function as associative array', CRYPT_RSA_ERROR_WRONG_PARAMS); +            return false; +        } + +        if (isset($params['enc_key'])) { +            if (Crypt_RSA_Key::isValid($params['enc_key'])) { +                $this->_enc_key = $params['enc_key']; +            } +            else { +                $this->pushError('wrong encryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +                return false; +            } +        } +        if (isset($params['dec_key'])) { +            if (Crypt_RSA_Key::isValid($params['dec_key'])) { +                $this->_dec_key = $params['dec_key']; +            } +            else { +                $this->pushError('wrong decryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +                return false; +            } +        } +        if (isset($params['private_key'])) { +            if (Crypt_RSA_Key::isValid($params['private_key'])) { +                if ($params['private_key']->getKeyType() != 'private') { +                    $this->pushError('private key must have "private" attribute', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); +                    return false; +                } +                $this->_private_key = $params['private_key']; +            } +            else { +                $this->pushError('wrong private key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +                return false; +            } +        } +        if (isset($params['public_key'])) { +            if (Crypt_RSA_Key::isValid($params['public_key'])) { +                if ($params['public_key']->getKeyType() != 'public') { +                    $this->pushError('public key must have "public" attribute', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); +                    return false; +                } +                $this->_public_key = $params['public_key']; +            } +            else { +                $this->pushError('wrong public key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +                return false; +            } +        } +        if (isset($params['hash_func'])) { +            if (!function_exists($params['hash_func'])) { +                $this->pushError('cannot find hash function with name [' . $params['hash_func'] . ']', CRYPT_RSA_ERROR_WRONG_HASH_FUNC); +                return false; +            } +            $this->_hash_func = $params['hash_func']; +        } +        return true; // all ok +    } + +    /** +     * Ecnrypts $plain_data by the key $this->_enc_key or $key. +     * +     * @param string $plain_data  data, which must be encrypted +     * @param object $key         encryption key (object of Crypt_RSA_Key class) +     * @return mixed +     *         encrypted data as string on success or false on error +     * +     * @access public +     */ +    function encrypt($plain_data, $key = null) +    { +        $enc_data = $this->encryptBinary($plain_data, $key); +        if ($enc_data !== false) { +            return base64_encode($enc_data); +        } +        // error during encripting data +        return false; +    } + +    /** +     * Ecnrypts $plain_data by the key $this->_enc_key or $key. +     * +     * @param string $plain_data  data, which must be encrypted +     * @param object $key         encryption key (object of Crypt_RSA_Key class) +     * @return mixed +     *         encrypted data as binary string on success or false on error +     * +     * @access public +     */ +    function encryptBinary($plain_data, $key = null) +    { +        if (is_null($key)) { +            // use current encryption key +            $key = $this->_enc_key; +        } +        else if (!Crypt_RSA_Key::isValid($key)) { +            $this->pushError('invalid encryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +            return false; +        } + +        // append tail \x01 to plain data. It needs for correctly decrypting of data +        $plain_data .= "\x01"; + +        $plain_data = $this->_math_obj->bin2int($plain_data); +        $exp = $this->_math_obj->bin2int($key->getExponent()); +        $modulus = $this->_math_obj->bin2int($key->getModulus()); + +        // divide plain data into chunks +        $data_len = $this->_math_obj->bitLen($plain_data); +        $chunk_len = $key->getKeyLength() - 1; +        $block_len = (int) ceil($chunk_len / 8); +        $curr_pos = 0; +        $enc_data = ''; +        while ($curr_pos < $data_len) { +            $tmp = $this->_math_obj->subint($plain_data, $curr_pos, $chunk_len); +            $enc_data .= str_pad( +                $this->_math_obj->int2bin($this->_math_obj->powmod($tmp, $exp, $modulus)), +                $block_len, +                "\0" +            ); +            $curr_pos += $chunk_len; +        } +        return $enc_data; +    } + +    /** +     * Decrypts $enc_data by the key $this->_dec_key or $key. +     * +     * @param string $enc_data  encrypted data as string +     * @param object $key       decryption key (object of RSA_Crypt_Key class) +     * @return mixed +     *         decrypted data as string on success or false on error +     * +     * @access public +     */ +    function decrypt($enc_data, $key = null) +    { +        $enc_data = base64_decode($enc_data); +        return $this->decryptBinary($enc_data, $key); +    } + +    /** +     * Decrypts $enc_data by the key $this->_dec_key or $key. +     * +     * @param string $enc_data  encrypted data as binary string +     * @param object $key       decryption key (object of RSA_Crypt_Key class) +     * @return mixed +     *         decrypted data as string on success or false on error +     * +     * @access public +     */ +    function decryptBinary($enc_data, $key = null) +    { +        if (is_null($key)) { +            // use current decryption key +            $key = $this->_dec_key; +        } +        else if (!Crypt_RSA_Key::isValid($key)) { +            $this->pushError('invalid decryption key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +            return false; +        } + +        $exp = $this->_math_obj->bin2int($key->getExponent()); +        $modulus = $this->_math_obj->bin2int($key->getModulus()); + +        $data_len = strlen($enc_data); +        $chunk_len = $key->getKeyLength() - 1; +        $block_len = (int) ceil($chunk_len / 8); +        $curr_pos = 0; +        $bit_pos = 0; +        $plain_data = $this->_math_obj->bin2int("\0"); +        while ($curr_pos < $data_len) { +            $tmp = $this->_math_obj->bin2int(substr($enc_data, $curr_pos, $block_len)); +            $tmp = $this->_math_obj->powmod($tmp, $exp, $modulus); +            $plain_data = $this->_math_obj->bitOr($plain_data, $tmp, $bit_pos); +            $bit_pos += $chunk_len; +            $curr_pos += $block_len; +        } +        $result = $this->_math_obj->int2bin($plain_data); + +        // delete tail, containing of \x01 +        $tail = ord($result{strlen($result) - 1}); +        if ($tail != 1) { +            $this->pushError("Error tail of decrypted text = {$tail}. Expected 1", CRYPT_RSA_ERROR_WRONG_TAIL); +            return false; +        } +        return substr($result, 0, -1); +    } + +    /** +     * Creates sign for document $document, using $this->_private_key or $private_key +     * as private key and $this->_hash_func or $hash_func as hash function. +     * +     * @param string $document     document, which must be signed +     * @param object $private_key  private key (object of Crypt_RSA_Key type) +     * @param string $hash_func    name of hash function, which will be used during signing +     * @return mixed +     *         signature of $document as string on success or false on error +     * +     * @access public +     */ +    function createSign($document, $private_key = null, $hash_func = null) +    { +        // check private key +        if (is_null($private_key)) { +            $private_key = $this->_private_key; +        } +        else if (!Crypt_RSA_Key::isValid($private_key)) { +            $this->pushError('invalid private key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +            return false; +        } +        if ($private_key->getKeyType() != 'private') { +            $this->pushError('signing key must be private', CRYPT_RSA_ERROR_NEED_PRV_KEY); +            return false; +        } + +        // check hash_func +        if (is_null($hash_func)) { +            $hash_func = $this->_hash_func; +        } +        if (!function_exists($hash_func)) { +            $this->pushError("cannot find hash function with name [$hash_func]", CRYPT_RSA_ERROR_WRONG_HASH_FUNC); +            return false; +        } + +        return $this->encrypt($hash_func($document), $private_key); +    } + +    /** +     * Validates $signature for document $document with public key $this->_public_key +     * or $public_key and hash function $this->_hash_func or $hash_func. +     * +     * @param string $document    document, signature of which must be validated +     * @param string $signature   signature, which must be validated +     * @param object $public_key  public key (object of Crypt_RSA_Key class) +     * @param string $hash_func   hash function, which will be used during validating signature +     * @return mixed +     *         true, if signature of document is valid +     *         false, if signature of document is invalid +     *         null on error +     * +     * @access public +     */ +    function validateSign($document, $signature, $public_key = null, $hash_func = null) +    { +        // check public key +        if (is_null($public_key)) { +            $public_key = $this->_public_key; +        } +        else if (!Crypt_RSA_Key::isValid($public_key)) { +            $this->pushError('invalid public key. It must be an object of Crypt_RSA_Key class', CRYPT_RSA_ERROR_WRONG_KEY); +            return null; +        } +        if ($public_key->getKeyType() != 'public') { +            $this->pushError('validating key must be public', CRYPT_RSA_ERROR_NEED_PUB_KEY); +            return null; +        } + +        // check hash_func +        if (is_null($hash_func)) { +            $hash_func = $this->_hash_func; +        } +        if (!function_exists($hash_func)) { +            $this->pushError("cannot find hash function with name [$hash_func]", CRYPT_RSA_ERROR_WRONG_HASH_FUNC); +            return null; +        } + +        return $hash_func($document) == $this->decrypt($signature, $public_key); +    } +} + +?>
\ No newline at end of file diff --git a/mod/openid_server/Crypt/RSA/ErrorHandler.php b/mod/openid_server/Crypt/RSA/ErrorHandler.php new file mode 100644 index 000000000..8f39741e0 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/ErrorHandler.php @@ -0,0 +1,234 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   CVS: $Id: ErrorHandler.php,v 1.4 2009/01/05 08:30:29 clockwerx Exp $ + * @link      http://pear.php.net/package/Crypt_RSA + */ + +/** + * uses PEAR's error handling + */ +require_once 'PEAR.php'; + +/** + * cannot load required extension for math wrapper + */ +define('CRYPT_RSA_ERROR_NO_EXT', 1); + +/** + * cannot load any math wrappers. + * Possible reasons: + *  - there is no any wrappers (they must exist in Crypt/RSA/Math folder ) + *  - all available wrappers are incorrect (read docs/Crypt_RSA/docs/math_wrappers.txt ) + *  - cannot load any extension, required by available wrappers + */ +define('CRYPT_RSA_ERROR_NO_WRAPPERS', 2); + +/** + * cannot find file, containing requested math wrapper + */ +define('CRYPT_RSA_ERROR_NO_FILE', 3); + +/** + * cannot find math wrapper class in the math wrapper file + */ +define('CRYPT_RSA_ERROR_NO_CLASS', 4); + +/** + * invalid key type passed to function (it must be 'public' or 'private') + */ +define('CRYPT_RSA_ERROR_WRONG_KEY_TYPE', 5); + +/** + * key modulus must be greater than key exponent + */ +define('CRYPT_RSA_ERROR_EXP_GE_MOD', 6); + +/** + * missing $key_len parameter in Crypt_RSA_KeyPair::generate($key_len) function + */ +define('CRYPT_RSA_ERROR_MISSING_KEY_LEN', 7); + +/** + * wrong key object passed to function (it must be an object of Crypt_RSA_Key class) + */ +define('CRYPT_RSA_ERROR_WRONG_KEY', 8); + +/** + * wrong name of hash function passed to Crypt_RSA::setParams() function + */ +define('CRYPT_RSA_ERROR_WRONG_HASH_FUNC', 9); + +/** + * key, used for signing, must be private + */ +define('CRYPT_RSA_ERROR_NEED_PRV_KEY', 10); + +/** + * key, used for sign validating, must be public + */ +define('CRYPT_RSA_ERROR_NEED_PUB_KEY', 11); + +/** + * parameters must be passed to function as associative array + */ +define('CRYPT_RSA_ERROR_WRONG_PARAMS', 12); + +/** + * error tail of decrypted text. Maybe, wrong decryption key? + */ +define('CRYPT_RSA_ERROR_WRONG_TAIL', 13); + +/** + * Crypt_RSA_ErrorHandler class. + * + * This class is used as base for Crypt_RSA, Crypt_RSA_Key + * and Crypt_RSA_KeyPair classes. + * + * It provides following functions: + *   - isError() - returns true, if list contains errors, else returns false + *   - getErrorList() - returns error list + *   - getLastError() - returns last error from error list or false, if list is empty + *   - pushError($errstr) - pushes $errstr into the error list + *   - setErrorHandler($new_error_handler) - sets error handler function + *   - getErrorHandler() - returns name of error handler function + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   Release: @package_version@ + * @link      http://pear.php.net/package/Crypt_RSA + * @access    public + */ +class Crypt_RSA_ErrorHandler +{ +    /** +     * array of error objects, pushed by $this->pushError() +     * +     * @var array +     * @access private +     */ +    var $_errors = array(); + +    /** +     * name of error handler - function, which calls on $this->pushError() call +     * +     * @var string +     * @access private +     */ +    var $_error_handler = ''; + +    /** +     * Returns true if list of errors is not empty, else returns false +     * +     * @param mixed $err Check if the object is an error +     * +     * @return bool    true, if list of errors is not empty or $err is PEAR_Error object, else false +     * @access public +     */ +    function isError($err = null) +    { +        return is_null($err) ? (sizeof($this->_errors) > 0) : PEAR::isError($err); +    } + +    /** +     * Returns list of all errors, pushed to error list by $this->pushError() +     * +     * @return array    list of errors (usually it contains objects of PEAR_Error class) +     * @access public +     */ +    function getErrorList() +    { +        return $this->_errors; +    } + +    /** +     * Returns last error from errors list or false, if list is empty +     * +     * @return mixed +     *         last error from errors list (usually it is PEAR_Error object) +     *         or false, if list is empty. +     * +     * @access public +     */ +    function getLastError() +    { +        $len = sizeof($this->_errors); +        return $len ? $this->_errors[$len - 1] : false; +    } + +    /** +     * pushes error object $error to the error list +     * +     * @param string $errstr error string +     * @param int    $errno  error number +     * +     * @return bool          true on success, false on error +     * @access public +     */ +    function pushError($errstr, $errno = 0) +    { +        $this->_errors[] = PEAR::raiseError($errstr, $errno); + +        if ($this->_error_handler != '') { +            // call user defined error handler +            $func = $this->_error_handler; +            $func($this); +        } +        return true; +    } + +    /** +     * sets error handler to function with name $func_name. +     * Function $func_name must accept one parameter - current +     * object, which triggered error. +     * +     * @param string $func_name name of error handler function +     * +     * @return bool             true on success, false on error +     * @access public +     */ +    function setErrorHandler($func_name = '') +    { +        if ($func_name == '') { +            $this->_error_handler = ''; +        } +        if (!function_exists($func_name)) { +            return false; +        } +        $this->_error_handler = $func_name; +        return true; +    } + +    /** +     * returns name of current error handler, or null if there is no error handler +     * +     * @return mixed  error handler name as string or null, if there is no error handler +     * @access public +     */ +    function getErrorHandler() +    { +        return $this->_error_handler; +    } +} + +?> diff --git a/mod/openid_server/Crypt/RSA/Key.php b/mod/openid_server/Crypt/RSA/Key.php new file mode 100644 index 000000000..72a71e2d0 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/Key.php @@ -0,0 +1,314 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   CVS: $Id: Key.php,v 1.6 2009/01/05 08:30:29 clockwerx Exp $ + * @link      http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for RSA math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * Crypt_RSA_Key class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + *  - getKeyLength() - returns bit key length + *  - getExponent() - returns key exponent as binary string + *  - getModulus() - returns key modulus as binary string + *  - getKeyType() - returns type of the key (public or private) + *  - toString() - returns serialized key as string + *  - fromString($key_str) - static function; returns key, unserialized from string + *  - isValid($key) - static function for validating of $key + * + * Example usage: + *    // create new 1024-bit key pair + *    $key_pair = new Crypt_RSA_KeyPair(1024); + *  + *    // get public key (its class is Crypt_RSA_Key) + *    $key = $key_pair->getPublicKey(); + * + *    // get key length + *    $len = $key->getKeyLength(); + * + *    // get modulus as string + *    $modulus = $key->getModulus(); + * + *    // get exponent as string + *    $exponent = $key->getExponent(); + * + *    // get string represenation of key (use it instead of serialization of Crypt_RSA_Key object) + *    $key_in_str = $key->toString(); + * + *    // restore key object from string using 'BigInt' math wrapper + *    $key = Crypt_RSA_Key::fromString($key_in_str, 'BigInt'); + * + *    // error check + *    if ($key->isError()) { + *        echo "error while unserializing key object:\n"; + *        $erorr = $key->getLastError(); + *        echo $error->getMessage(), "\n"; + *    } + * + *    // validate key + *    if (Crypt_RSA_Key::isValid($key)) echo 'valid key'; + *    else echo 'invalid key'; + * + *    // using factory() method instead of constructor (it returns PEAR_Error object on failure) + *    $rsa_obj = &Crypt_RSA_Key::factory($modulus, $exp, $key_type); + *    if (PEAR::isError($rsa_obj)) { + *        echo "error: ", $rsa_obj->getMessage(), "\n"; + *    } + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   Release: @package_version@ + * @link      http://pear.php.net/package/Crypt_RSA + * @access    public + */ +class Crypt_RSA_Key extends Crypt_RSA_ErrorHandler +{ +    /** +     * Reference to math wrapper object, which is used to +     * manipulate large integers in RSA algorithm. +     * +     * @var object of Crypt_RSA_Math_* class +     * @access private +     */ +    var $_math_obj; + +    /** +     * shared modulus +     * +     * @var string +     * @access private +     */ +    var $_modulus; + +    /** +     * exponent +     * +     * @var string +     * @access private +     */ +    var $_exp; + +    /** +     * key type (private or public) +     * +     * @var string +     * @access private +     */ +    var $_key_type; + +    /** +     * key length in bits +     * +     * @var int +     * @access private +     */ +    var $_key_len; + +    /** +     * Crypt_RSA_Key constructor. +     * +     * You should pass in the name of math wrapper, which will be used to +     *        perform different operations with big integers. +     *        See contents of Crypt/RSA/Math folder for examples of wrappers. +     *        Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * +     * @param string $modulus       key modulus +     * @param string $exp           key exponent +     * @param string $key_type      type of the key (public or private) +     * @param string $wrapper_name  wrapper to use +     * @param string $error_handler name of error handler function +     * +     * @access public +     */ +    function Crypt_RSA_Key($modulus, $exp, $key_type, $wrapper_name = 'default', $error_handler = '') +    { +        // set error handler +        $this->setErrorHandler($error_handler); +        // try to load math wrapper $wrapper_name +        $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); +        if ($this->isError($obj)) { +            // error during loading of math wrapper +            $this->pushError($obj); // push error object into error list +            return; +        } +        $this->_math_obj = &$obj; + +        $this->_modulus = $modulus; +        $this->_exp = $exp; + +        if (!in_array($key_type, array('private', 'public'))) { +            $this->pushError('invalid key type. It must be private or public', CRYPT_RSA_ERROR_WRONG_KEY_TYPE); +            return; +        } +        $this->_key_type = $key_type; + +        /* check length of modulus & exponent ( abs(modulus) > abs(exp) ) */ +        $mod_num = $this->_math_obj->bin2int($this->_modulus); +        $exp_num = $this->_math_obj->bin2int($this->_exp); + +        if ($this->_math_obj->cmpAbs($mod_num, $exp_num) <= 0) { +            $this->pushError('modulus must be greater than exponent', CRYPT_RSA_ERROR_EXP_GE_MOD); +            return; +        } +        // determine key length +        $this->_key_len = $this->_math_obj->bitLen($mod_num); +    } + +    /** +     * Crypt_RSA_Key factory. +     * +     * @param string $modulus       key modulus +     * @param string $exp           key exponent +     * @param string $key_type      type of the key (public or private) +     * @param string $wrapper_name  wrapper to use +     * @param string $error_handler name of error handler function +     * +     * @return object   new Crypt_RSA_Key object on success or PEAR_Error object on failure +     * @access public +     */ +    function factory($modulus, $exp, $key_type, $wrapper_name = 'default', $error_handler = '') +    { +        $obj = new Crypt_RSA_Key($modulus, $exp, $key_type, $wrapper_name, $error_handler); +        if ($obj->isError()) { +            // error during creating a new object. Retrurn PEAR_Error object +            return $obj->getLastError(); +        } +        // object created successfully. Return it +        return $obj; +    } + +    /** +     * Calculates bit length of the key +     * +     * @return int    bit length of key +     * @access public +     */ +    function getKeyLength() +    { +        return $this->_key_len; +    } + +    /** +     * Returns modulus part of the key as binary string, +     * which can be used to construct new Crypt_RSA_Key object. +     * +     * @return string  modulus as binary string +     * @access public +     */ +    function getModulus() +    { +        return $this->_modulus; +    } + +    /** +     * Returns exponent part of the key as binary string, +     * which can be used to construct new Crypt_RSA_Key object. +     * +     * @return string  exponent as binary string +     * @access public +     */ +    function getExponent() +    { +        return $this->_exp; +    } + +    /** +     * Returns key type (public, private) +     * +     * @return string  key type (public, private) +     * @access public +     */ +    function getKeyType() +    { +        return $this->_key_type; +    } + +    /** +     * Returns string representation of key +     * +     * @return string  key, serialized to string +     * @access public +     */ +    function toString() +    { +        return base64_encode( +            serialize( +                array($this->_modulus, $this->_exp, $this->_key_type) +            ) +        ); +    } + +    /** +     * Returns Crypt_RSA_Key object, unserialized from +     * string representation of key. +     * +     * optional parameter $wrapper_name - is the name of math wrapper, +     * which will be used during unserialization of this object. +     * +     * This function can be called statically: +     *     $key = Crypt_RSA_Key::fromString($key_in_string, 'BigInt'); +     * +     * @param string $key_str      RSA key, serialized into string +     * @param string $wrapper_name optional math wrapper name +     * +     * @return object        key as Crypt_RSA_Key object +     * @access public +     * @static +     */ +    function fromString($key_str, $wrapper_name = 'default') +    { +        list($modulus, $exponent, $key_type) = unserialize(base64_decode($key_str)); +        $obj = new Crypt_RSA_Key($modulus, $exponent, $key_type, $wrapper_name); +        return $obj; +    } + +    /** +     * Validates key +     * This function can be called statically: +     *    $is_valid = Crypt_RSA_Key::isValid($key) +     * +     * Returns true, if $key is valid Crypt_RSA key, else returns false +     * +     * @param object $key Crypt_RSA_Key object for validating +     * +     * @return bool        true if $key is valid, else false +     * @access public +     */ +    function isValid($key) +    { +        return (is_object($key) && strtolower(get_class($key)) === strtolower(__CLASS__)); +    } +} + +?> diff --git a/mod/openid_server/Crypt/RSA/KeyPair.php b/mod/openid_server/Crypt/RSA/KeyPair.php new file mode 100644 index 000000000..ecc0b7dc7 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/KeyPair.php @@ -0,0 +1,804 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   CVS: $Id: KeyPair.php,v 1.7 2009/01/05 08:30:29 clockwerx Exp $ + * @link      http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * loader for RSA math wrappers + */ +require_once 'Crypt/RSA/MathLoader.php'; + +/** + * helper class for single key managing + */ +require_once 'Crypt/RSA/Key.php'; + +/** + * Crypt_RSA_KeyPair class, derived from Crypt_RSA_ErrorHandler + * + * Provides the following functions: + *  - generate($key) - generates new key pair + *  - getPublicKey() - returns public key + *  - getPrivateKey() - returns private key + *  - getKeyLength() - returns bit key length + *  - setRandomGenerator($func_name) - sets random generator to $func_name + *  - fromPEMString($str) - retrieves keypair from PEM-encoded string + *  - toPEMString() - stores keypair to PEM-encoded string + *  - isEqual($keypair2) - compares current keypair to $keypair2 + * + * Example usage: + *    // create new 1024-bit key pair + *    $key_pair = new Crypt_RSA_KeyPair(1024); + * + *    // error check + *    if ($key_pair->isError()) { + *        echo "error while initializing Crypt_RSA_KeyPair object:\n"; + *        $erorr = $key_pair->getLastError(); + *        echo $error->getMessage(), "\n"; + *    } + * + *    // get public key + *    $public_key = $key_pair->getPublicKey(); + *  + *    // get private key + *    $private_key = $key_pair->getPrivateKey(); + *  + *    // generate new 512-bit key pair + *    $key_pair->generate(512); + * + *    // error check + *    if ($key_pair->isError()) { + *        echo "error while generating key pair:\n"; + *        $erorr = $key_pair->getLastError(); + *        echo $error->getMessage(), "\n"; + *    } + * + *    // get key pair length + *    $length = $key_pair->getKeyLength(); + * + *    // set random generator to $func_name, where $func_name + *    // consists name of random generator function. See comments + *    // before setRandomGenerator() method for details + *    $key_pair->setRandomGenerator($func_name); + * + *    // error check + *    if ($key_pair->isError()) { + *        echo "error while changing random generator:\n"; + *        $erorr = $key_pair->getLastError(); + *        echo $error->getMessage(), "\n"; + *    } + * + *    // using factory() method instead of constructor (it returns PEAR_Error object on failure) + *    $rsa_obj = &Crypt_RSA_KeyPair::factory($key_len); + *    if (PEAR::isError($rsa_obj)) { + *        echo "error: ", $rsa_obj->getMessage(), "\n"; + *    } + * + *    // read key pair from PEM-encoded string: + *    $str = "-----BEGIN RSA PRIVATE KEY-----" + *         . "MCsCAQACBHr5LDkCAwEAAQIEBc6jbQIDAOCfAgMAjCcCAk3pAgJMawIDAL41" + *         . "-----END RSA PRIVATE KEY-----"; + *    $keypair = Crypt_RSA_KeyPair::fromPEMString($str); + * + *    // read key pair from .pem file 'private.pem': + *    $str = file_get_contents('private.pem'); + *    $keypair = Crypt_RSA_KeyPair::fromPEMString($str); + * + *    // generate and write 1024-bit key pair to .pem file 'private_new.pem' + *    $keypair = new Crypt_RSA_KeyPair(1024); + *    $str = $keypair->toPEMString(); + *    file_put_contents('private_new.pem', $str); + * + *    // compare $keypair1 to $keypair2 + *    if ($keypair1->isEqual($keypair2)) { + *        echo "keypair1 = keypair2\n"; + *    } + *    else { + *        echo "keypair1 != keypair2\n"; + *    } + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright 2005 Alexander Valyalkin + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   Release: @package_version@ + * @link      http://pear.php.net/package/Crypt_RSA + * @access    public + */ +class Crypt_RSA_KeyPair extends Crypt_RSA_ErrorHandler +{ +    /** +     * Reference to math wrapper object, which is used to +     * manipulate large integers in RSA algorithm. +     * +     * @var object of Crypt_RSA_Math_* class +     * @access private +     */ +    var $_math_obj; + +    /** +     * length of each key in the key pair +     * +     * @var int +     * @access private +     */ +    var $_key_len; + +    /** +     * public key +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_public_key; + +    /** +     * private key +     * +     * @var object of Crypt_RSA_KEY class +     * @access private +     */ +    var $_private_key; + +    /** +     * name of function, which is used as random generator +     * +     * @var string +     * @access private +     */ +    var $_random_generator; + +    /** +     * RSA keypair attributes [version, n, e, d, p, q, dmp1, dmq1, iqmp] as associative array +     * +     * @var array +     * @access private +     */ +    var $_attrs; + +    /** +     * Returns names of keypair attributes from $this->_attrs array +     * +     * @return array  Array of keypair attributes names +     * @access private +     */ +    function _get_attr_names()  +    { +        return array('version', 'n', 'e', 'd', 'p', 'q', 'dmp1', 'dmq1', 'iqmp'); +    } + +    /** +     * Parses ASN.1 string [$str] starting form position [$pos]. +     * Returns tag and string value of parsed object. +     * +     * @param string                 $str +     * @param int                    &$pos +     * @param Crypt_RSA_ErrorHandler &$err_handler +     * +     * @return mixed    Array('tag' => ..., 'str' => ...) on success, false on error +     * @access private +     */ +    function _ASN1Parse($str, &$pos, &$err_handler) +    { +        $max_pos = strlen($str); +        if ($max_pos < 2) { +            $err_handler->pushError("ASN.1 string too short"); +            return false; +        } + +        // get ASN.1 tag value +        $tag = ord($str[$pos++]) & 0x1f; +        if ($tag == 0x1f) { +            $tag = 0; +            do { +                $n = ord($str[$pos++]); +                $tag <<= 7; +                $tag |= $n & 0x7f; +            } while (($n & 0x80) && $pos < $max_pos); +        } +        if ($pos >= $max_pos) { +            $err_handler->pushError("ASN.1 string too short"); +            return false; +        } + +        // get ASN.1 object length +        $len = ord($str[$pos++]); +        if ($len & 0x80) { +            $n = $len & 0x1f; +            $len = 0; +            while ($n-- && $pos < $max_pos) { +                $len <<= 8; +                $len |= ord($str[$pos++]); +            } +        } +        if ($pos >= $max_pos || $len > $max_pos - $pos) { +            $err_handler->pushError("ASN.1 string too short"); +            return false; +        } + +        // get string value of ASN.1 object +        $str = substr($str, $pos, $len); + +        return array( +            'tag' => $tag, +            'str' => $str, +        ); +    } + +    /** +     * Parses ASN.1 sting [$str] starting from position [$pos]. +     * Returns string representation of number, which can be passed +     * in bin2int() function of math wrapper. +     * +     * @param string                 $str +     * @param int                    &$pos +     * @param Crypt_RSA_ErrorHandler &$err_handler +     * +     * @return mixed   string representation of parsed number on success, false on error +     * @access private +     */ +    function _ASN1ParseInt($str, &$pos, &$err_handler) +    { +        $tmp = Crypt_RSA_KeyPair::_ASN1Parse($str, $pos, $err_handler); +        if ($err_handler->isError()) { +            return false; +        } +        if ($tmp['tag'] != 0x02) { +            $errstr = sprintf("wrong ASN tag value: 0x%02x. Expected 0x02 (INTEGER)", $tmp['tag']); +            $err_handler->pushError($errstr); +            return false; +        } +        $pos += strlen($tmp['str']); + +        return strrev($tmp['str']); +    } + +    /** +     * Constructs ASN.1 string from tag $tag and object $str +     * +     * @param string $str            ASN.1 object string +     * @param int    $tag            ASN.1 tag value +     * @param bool   $is_constructed  +     * @param bool   $is_private  +     * +     * @return ASN.1-encoded string +     * @access private +     */ +    function _ASN1Store($str, $tag, $is_constructed = false, $is_private = false) +    { +        $out = ''; + +        // encode ASN.1 tag value +        $tag_ext = ($is_constructed ? 0x20 : 0) | ($is_private ? 0xc0 : 0); +        if ($tag < 0x1f) { +            $out .= chr($tag | $tag_ext); +        } else { +            $out .= chr($tag_ext | 0x1f); +            $tmp = chr($tag & 0x7f); +            $tag >>= 7; +            while ($tag) { +                $tmp .= chr(($tag & 0x7f) | 0x80); +                $tag >>= 7; +            } +            $out .= strrev($tmp); +        } + +        // encode ASN.1 object length +        $len = strlen($str); +        if ($len < 0x7f) { +            $out .= chr($len); +        } else { +            $tmp = ''; +            $n = 0; +            while ($len) { +                $tmp .= chr($len & 0xff); +                $len >>= 8; +                $n++; +            } +            $out .= chr($n | 0x80); +            $out .= strrev($tmp); +        } + +        return $out . $str; +    } + +    /** +     * Constructs ASN.1 string from binary representation of big integer +     * +     * @param string $str binary representation of big integer +     * +     * @return ASN.1-encoded string +     * @access private +     */ +    function _ASN1StoreInt($str) +    { +        $str = strrev($str); +        return Crypt_RSA_KeyPair::_ASN1Store($str, 0x02); +    } + +    /** +     * Crypt_RSA_KeyPair constructor. +     * +     * Wrapper: name of math wrapper, which will be used to +     *        perform different operations with big integers. +     *        See contents of Crypt/RSA/Math folder for examples of wrappers. +     *        Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * +     * @param int      $key_len          bit length of key pair, which will be generated in constructor +     * @param string   $wrapper_name     wrapper name +     * @param string   $error_handler    name of error handler function +     * @param callback $random_generator function which will be used as random generator +     * +     * @access public +     */ +    function Crypt_RSA_KeyPair($key_len, $wrapper_name = 'default', $error_handler = '', $random_generator = null) +    { +        // set error handler +        $this->setErrorHandler($error_handler); +        // try to load math wrapper +        $obj = &Crypt_RSA_MathLoader::loadWrapper($wrapper_name); +        if ($this->isError($obj)) { +            // error during loading of math wrapper +            $this->pushError($obj); +            return; +        } +        $this->_math_obj = &$obj; + +        // set random generator +        if (!$this->setRandomGenerator($random_generator)) { +            // error in setRandomGenerator() function +            return; +        } + +        if (is_array($key_len)) { +            // ugly BC hack - it is possible to pass RSA private key attributes [version, n, e, d, p, q, dmp1, dmq1, iqmp] +            // as associative array instead of key length to Crypt_RSA_KeyPair constructor +            $rsa_attrs = $key_len; + +            // convert attributes to big integers +            $attr_names = $this->_get_attr_names(); +            foreach ($attr_names as $attr) { +                if (!isset($rsa_attrs[$attr])) { +                    $this->pushError("missing required RSA attribute [$attr]"); +                    return; +                } +                ${$attr} = $this->_math_obj->bin2int($rsa_attrs[$attr]); +            } + +            // check primality of p and q +            if (!$this->_math_obj->isPrime($p)) { +                $this->pushError("[p] must be prime"); +                return; +            } +            if (!$this->_math_obj->isPrime($q)) { +                $this->pushError("[q] must be prime"); +                return; +            } + +            // check n = p * q +            $n1 = $this->_math_obj->mul($p, $q); +            if ($this->_math_obj->cmpAbs($n, $n1)) { +                $this->pushError("n != p * q"); +                return; +            } + +            // check e * d = 1 mod (p-1) * (q-1) +            $p1 = $this->_math_obj->dec($p); +            $q1 = $this->_math_obj->dec($q); +            $p1q1 = $this->_math_obj->mul($p1, $q1); +            $ed = $this->_math_obj->mul($e, $d); +            $one = $this->_math_obj->mod($ed, $p1q1); +            if (!$this->_math_obj->isOne($one)) { +                $this->pushError("e * d != 1 mod (p-1)*(q-1)"); +                return; +            } + +            // check dmp1 = d mod (p-1) +            $dmp = $this->_math_obj->mod($d, $p1); +            if ($this->_math_obj->cmpAbs($dmp, $dmp1)) { +                $this->pushError("dmp1 != d mod (p-1)"); +                return; +            } + +            // check dmq1 = d mod (q-1) +            $dmq = $this->_math_obj->mod($d, $q1); +            if ($this->_math_obj->cmpAbs($dmq, $dmq1)) { +                $this->pushError("dmq1 != d mod (q-1)"); +                return; +            } + +            // check iqmp = 1/q mod p +            $q1 = $this->_math_obj->invmod($iqmp, $p); +            if ($this->_math_obj->cmpAbs($q, $q1)) { +                $this->pushError("iqmp != 1/q mod p"); +                return; +            } + +            // try to create public key object +            $public_key = &new Crypt_RSA_Key($rsa_attrs['n'], $rsa_attrs['e'], 'public', $wrapper_name, $error_handler); +            if ($public_key->isError()) { +                // error during creating public object +                $this->pushError($public_key->getLastError()); +                return; +            } + +            // try to create private key object +            $private_key = &new Crypt_RSA_Key($rsa_attrs['n'], $rsa_attrs['d'], 'private', $wrapper_name, $error_handler); +            if ($private_key->isError()) { +                // error during creating private key object +                $this->pushError($private_key->getLastError()); +                return; +            } + +            $this->_public_key = $public_key; +            $this->_private_key = $private_key; +            $this->_key_len = $public_key->getKeyLength(); +            $this->_attrs = $rsa_attrs; +        } else { +            // generate key pair +            if (!$this->generate($key_len)) { +                // error during generating key pair +                return; +            } +        } +    } + +    /** +     * Crypt_RSA_KeyPair factory. +     * +     * Wrapper - Name of math wrapper, which will be used to +     *        perform different operations with big integers. +     *        See contents of Crypt/RSA/Math folder for examples of wrappers. +     *        Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * +     * @param int      $key_len          bit length of key pair, which will be generated in constructor +     * @param string   $wrapper_name     wrapper name +     * @param string   $error_handler    name of error handler function +     * @param callback $random_generator function which will be used as random generator +     * +     * @return object   new Crypt_RSA_KeyPair object on success or PEAR_Error object on failure +     * @access public +     */ +    function &factory($key_len, $wrapper_name = 'default', $error_handler = '', $random_generator = null) +    { +        $obj = &new Crypt_RSA_KeyPair($key_len, $wrapper_name, $error_handler, $random_generator); +        if ($obj->isError()) { +            // error during creating a new object. Return PEAR_Error object +            return $obj->getLastError(); +        } +        // object created successfully. Return it +        return $obj; +    } + +    /** +     * Generates new Crypt_RSA key pair with length $key_len. +     * If $key_len is missed, use an old key length from $this->_key_len +     * +     * @param int $key_len bit length of key pair, which will be generated +     * +     * @return bool         true on success or false on error +     * @access public +     */ +    function generate($key_len = null) +    { +        if (is_null($key_len)) { +            // use an old key length +            $key_len = $this->_key_len; +            if (is_null($key_len)) { +                $this->pushError('missing key_len parameter', CRYPT_RSA_ERROR_MISSING_KEY_LEN); +                return false; +            } +        } + +        // minimal key length is 8 bit ;) +        if ($key_len < 8) { +            $key_len = 8; +        } +        // store key length in the _key_len property +        $this->_key_len = $key_len; + +        // set [e] to 0x10001 (65537) +        $e = $this->_math_obj->bin2int("\x01\x00\x01"); + +        // generate [p], [q] and [n] +        $p_len = intval(($key_len + 1) / 2); +        $q_len = $key_len - $p_len; +        $p1 = $q1 = 0; +        do { +            // generate prime number [$p] with length [$p_len] with the following condition: +            // GCD($e, $p - 1) = 1 +            do { +                $p = $this->_math_obj->getPrime($p_len, $this->_random_generator); +                $p1 = $this->_math_obj->dec($p); +                $tmp = $this->_math_obj->GCD($e, $p1); +            } while (!$this->_math_obj->isOne($tmp)); +            // generate prime number [$q] with length [$q_len] with the following conditions: +            // GCD($e, $q - 1) = 1 +            // $q != $p +            do { +                $q = $this->_math_obj->getPrime($q_len, $this->_random_generator); +                $q1 = $this->_math_obj->dec($q); +                $tmp = $this->_math_obj->GCD($e, $q1); +            } while (!$this->_math_obj->isOne($tmp) && !$this->_math_obj->cmpAbs($q, $p)); +            // if (p < q), then exchange them +            if ($this->_math_obj->cmpAbs($p, $q) < 0) { +                $tmp = $p; +                $p = $q; +                $q = $tmp; +                $tmp = $p1; +                $p1 = $q1; +                $q1 = $tmp; +            } +            // calculate n = p * q +            $n = $this->_math_obj->mul($p, $q); +        } while ($this->_math_obj->bitLen($n) != $key_len); + +        // calculate d = 1/e mod (p - 1) * (q - 1) +        $pq = $this->_math_obj->mul($p1, $q1); +        $d = $this->_math_obj->invmod($e, $pq); + +        // calculate dmp1 = d mod (p - 1) +        $dmp1 = $this->_math_obj->mod($d, $p1); + +        // calculate dmq1 = d mod (q - 1) +        $dmq1 = $this->_math_obj->mod($d, $q1); + +        // calculate iqmp = 1/q mod p +        $iqmp = $this->_math_obj->invmod($q, $p); + +        // store RSA keypair attributes +        $this->_attrs = array( +            'version' => "\x00", +            'n' => $this->_math_obj->int2bin($n), +            'e' => $this->_math_obj->int2bin($e), +            'd' => $this->_math_obj->int2bin($d), +            'p' => $this->_math_obj->int2bin($p), +            'q' => $this->_math_obj->int2bin($q), +            'dmp1' => $this->_math_obj->int2bin($dmp1), +            'dmq1' => $this->_math_obj->int2bin($dmq1), +            'iqmp' => $this->_math_obj->int2bin($iqmp), +        ); + +        $n = $this->_attrs['n']; +        $e = $this->_attrs['e']; +        $d = $this->_attrs['d']; + +        // try to create public key object +        $obj = &new Crypt_RSA_Key($n, $e, 'public', $this->_math_obj->getWrapperName(), $this->_error_handler); +        if ($obj->isError()) { +            // error during creating public object +            $this->pushError($obj->getLastError()); +            return false; +        } +        $this->_public_key = &$obj; + +        // try to create private key object +        $obj = &new Crypt_RSA_Key($n, $d, 'private', $this->_math_obj->getWrapperName(), $this->_error_handler); +        if ($obj->isError()) { +            // error during creating private key object +            $this->pushError($obj->getLastError()); +            return false; +        } +        $this->_private_key = &$obj; + +        return true; // key pair successfully generated +    } + +    /** +     * Returns public key from the pair +     * +     * @return object  public key object of class Crypt_RSA_Key +     * @access public +     */ +    function getPublicKey() +    { +        return $this->_public_key; +    } + +    /** +     * Returns private key from the pair +     * +     * @return object   private key object of class Crypt_RSA_Key +     * @access public +     */ +    function getPrivateKey() +    { +        return $this->_private_key; +    } + +    /** +     * Sets name of random generator function for key generation. +     * If parameter is skipped, then sets to default random generator. +     * +     * Random generator function must return integer with at least 8 lower +     * significant bits, which will be used as random values. +     * +     * @param string $random_generator name of random generator function +     * +     * @return bool                     true on success or false on error +     * @access public +     */ +    function setRandomGenerator($random_generator = null) +    { +        static $default_random_generator = null; + +        if (is_string($random_generator)) { +            // set user's random generator +            if (!function_exists($random_generator)) { +                $this->pushError("can't find random generator function with name [{$random_generator}]"); +                return false; +            } +            $this->_random_generator = $random_generator; +        } else { +            // set default random generator +            $this->_random_generator = is_null($default_random_generator) ? +                ($default_random_generator = create_function('', '$a=explode(" ",microtime());return(int)($a[0]*1000000);')) : +                $default_random_generator; +        } +        return true; +    } + +    /** +     * Returns length of each key in the key pair +     * +     * @return int  bit length of each key in key pair +     * @access public +     */ +    function getKeyLength() +    { +        return $this->_key_len; +    } + +    /** +     * Retrieves RSA keypair from PEM-encoded string, containing RSA private key. +     * Example of such string: +     * -----BEGIN RSA PRIVATE KEY----- +     * MCsCAQACBHtvbSECAwEAAQIEeYrk3QIDAOF3AgMAjCcCAmdnAgJMawIDALEk +     * -----END RSA PRIVATE KEY----- +     * +     * Wrapper: Name of math wrapper, which will be used to +     * perform different operations with big integers. +     * See contents of Crypt/RSA/Math folder for examples of wrappers. +     * Read docs/Crypt_RSA/docs/math_wrappers.txt for details. +     * +     * @param string $str           PEM-encoded string +     * @param string $wrapper_name  Wrapper name +     * @param string $error_handler name of error handler function +     * +     * @return Crypt_RSA_KeyPair object on success, PEAR_Error object on error +     * @access public +     * @static +     */ +    function &fromPEMString($str, $wrapper_name = 'default', $error_handler = '') +    { +        if (isset($this)) { +            if ($wrapper_name == 'default') { +                $wrapper_name = $this->_math_obj->getWrapperName(); +            } +            if ($error_handler == '') { +                $error_handler = $this->_error_handler; +            } +        } +        $err_handler = &new Crypt_RSA_ErrorHandler; +        $err_handler->setErrorHandler($error_handler); + +        // search for base64-encoded private key +        if (!preg_match('/-----BEGIN RSA PRIVATE KEY-----([^-]+)-----END RSA PRIVATE KEY-----/', $str, $matches)) { +            $err_handler->pushError("can't find RSA private key in the string [{$str}]"); +            return $err_handler->getLastError(); +        } + +        // parse private key. It is ASN.1-encoded +        $str = base64_decode($matches[1]); +        $pos = 0; +        $tmp = Crypt_RSA_KeyPair::_ASN1Parse($str, $pos, $err_handler); +        if ($err_handler->isError()) { +            return $err_handler->getLastError(); +        } +        if ($tmp['tag'] != 0x10) { +            $errstr = sprintf("wrong ASN tag value: 0x%02x. Expected 0x10 (SEQUENCE)", $tmp['tag']); +            $err_handler->pushError($errstr); +            return $err_handler->getLastError(); +        } + +        // parse ASN.1 SEQUENCE for RSA private key +        $attr_names = Crypt_RSA_KeyPair::_get_attr_names(); +        $n = sizeof($attr_names); +        $rsa_attrs = array(); +        for ($i = 0; $i < $n; $i++) { +            $tmp = Crypt_RSA_KeyPair::_ASN1ParseInt($str, $pos, $err_handler); +            if ($err_handler->isError()) { +                return $err_handler->getLastError(); +            } +            $attr = $attr_names[$i]; +            $rsa_attrs[$attr] = $tmp; +        } + +        // create Crypt_RSA_KeyPair object. +        $keypair = &new Crypt_RSA_KeyPair($rsa_attrs, $wrapper_name, $error_handler); +        if ($keypair->isError()) { +            return $keypair->getLastError(); +        } + +        return $keypair; +    } + +    /** +     * converts keypair to PEM-encoded string, which can be stroed in  +     * .pem compatible files, contianing RSA private key. +     * +     * @return string PEM-encoded keypair on success, false on error +     * @access public +     */ +    function toPEMString() +    { +        // store RSA private key attributes into ASN.1 string +        $str = ''; +        $attr_names = $this->_get_attr_names(); +        $n = sizeof($attr_names); +        $rsa_attrs = $this->_attrs; +        for ($i = 0; $i < $n; $i++) { +            $attr = $attr_names[$i]; +            if (!isset($rsa_attrs[$attr])) { +                $this->pushError("Cannot find value for ASN.1 attribute [$attr]"); +                return false; +            } +            $tmp = $rsa_attrs[$attr]; +            $str .= Crypt_RSA_KeyPair::_ASN1StoreInt($tmp); +        } + +        // prepend $str by ASN.1 SEQUENCE (0x10) header +        $str = Crypt_RSA_KeyPair::_ASN1Store($str, 0x10, true); + +        // encode and format PEM string +        $str = base64_encode($str); +        $str = chunk_split($str, 64, "\n"); +        return "-----BEGIN RSA PRIVATE KEY-----\n$str-----END RSA PRIVATE KEY-----\n"; +    } + +    /** +     * Compares keypairs in Crypt_RSA_KeyPair objects $this and $key_pair +     * +     * @param Crypt_RSA_KeyPair $key_pair  keypair to compare +     * +     * @return bool  true, if keypair stored in $this equal to keypair stored in $key_pair +     * @access public +     */ +    function isEqual($key_pair) +    { +        $attr_names = $this->_get_attr_names(); +        foreach ($attr_names as $attr) { +            if ($this->_attrs[$attr] != $key_pair->_attrs[$attr]) { +                return false; +            } +        } +        return true; +    } +} + +?> diff --git a/mod/openid_server/Crypt/RSA/Math/BCMath.php b/mod/openid_server/Crypt/RSA/Math/BCMath.php new file mode 100644 index 000000000..646ff6710 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/Math/BCMath.php @@ -0,0 +1,482 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version    1.2.0b + * @link       http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_BCMath class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for PHP BCMath extension. + * See http://php.net/manual/en/ref.bc.php for details. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @link       http://pear.php.net/package/Crypt_RSA + * @version    @package_version@ + * @access     public + */ +class Crypt_RSA_Math_BCMath +{ +    /** +     * error description +     * +     * @var string +     * @access public +     */ +    var $errstr = ''; + +    /** +     * Performs Miller-Rabin primality test for number $num  +     * with base $base. Returns true, if $num is strong pseudoprime +     * by base $base. Else returns false. +     * +     * @param string $num +     * @param string $base +     * @return bool +     * @access private +     */ +    function _millerTest($num, $base) +    { +        if (!bccomp($num, '1')) { +            // 1 is not prime ;) +            return false; +        } +        $tmp = bcsub($num, '1'); + +        $zero_bits = 0; +        while (!bccomp(bcmod($tmp, '2'), '0')) { +            $zero_bits++; +            $tmp = bcdiv($tmp, '2'); +        } + +        $tmp = $this->powmod($base, $tmp, $num); +        if (!bccomp($tmp, '1')) { +            // $num is probably prime +            return true; +        } + +        while ($zero_bits--) { +            if (!bccomp(bcadd($tmp, '1'), $num)) { +                // $num is probably prime +                return true; +            } +            $tmp = $this->powmod($tmp, '2', $num); +        } +        // $num is composite +        return false; +    } + +    /** +     * Crypt_RSA_Math_BCMath constructor. +     * Checks an existance of PHP BCMath extension. +     * On failure saves error description in $this->errstr +     * +     * @access public +     */ +    function Crypt_RSA_Math_BCMath() +    { +        if (!extension_loaded('bcmath')) { +            if (!@dl('bcmath.' . PHP_SHLIB_SUFFIX) && !@dl('php_bcmath.' . PHP_SHLIB_SUFFIX)) { +                // cannot load BCMath extension. Set error string +                $this->errstr = 'Crypt_RSA package requires the BCMath extension. See http://php.net/manual/en/ref.bc.php for details'; +                return; +            } +        } +    } + +    /** +     * Transforms binary representation of large integer into its native form. +     *  +     * Example of transformation: +     *    $str = "\x12\x34\x56\x78\x90"; +     *    $num = 0x9078563412; +     * +     * @param string $str +     * @return string +     * @access public +     */ +    function bin2int($str) +    { +        $result = '0'; +        $n = strlen($str); +        do { +            $result = bcadd(bcmul($result, '256'), ord($str{--$n})); +        } while ($n > 0); +        return $result; +    } + +    /** +     * Transforms large integer into binary representation. +     *  +     * Example of transformation: +     *    $num = 0x9078563412; +     *    $str = "\x12\x34\x56\x78\x90"; +     * +     * @param string $num +     * @return string +     * @access public +     */ +    function int2bin($num) +    { +        $result = ''; +        do { +            $result .= chr(bcmod($num, '256')); +            $num = bcdiv($num, '256'); +        } while (bccomp($num, '0')); +        return $result; +    } + +    /** +     * Calculates pow($num, $pow) (mod $mod) +     * +     * @param string $num +     * @param string $pow +     * @param string $mod +     * @return string +     * @access public +     */ +    function powmod($num, $pow, $mod) +    { +        if (function_exists('bcpowmod')) { +            // bcpowmod is only available under PHP5 +            return bcpowmod($num, $pow, $mod); +        } + +        // emulate bcpowmod +        $result = '1'; +        do { +            if (!bccomp(bcmod($pow, '2'), '1')) { +                $result = bcmod(bcmul($result, $num), $mod); +            } +            $num = bcmod(bcpow($num, '2'), $mod); +            $pow = bcdiv($pow, '2'); +        } while (bccomp($pow, '0')); +        return $result; +    } + +    /** +     * Calculates $num1 * $num2 +     * +     * @param string $num1 +     * @param string $num2 +     * @return string +     * @access public +     */ +    function mul($num1, $num2) +    { +        return bcmul($num1, $num2); +    } + +    /** +     * Calculates $num1 % $num2 +     * +     * @param string $num1 +     * @param string $num2 +     * @return string +     * @access public +     */ +    function mod($num1, $num2) +    { +        return bcmod($num1, $num2); +    } + +    /** +     * Compares abs($num1) to abs($num2). +     * Returns: +     *   -1, if abs($num1) < abs($num2) +     *   0, if abs($num1) == abs($num2) +     *   1, if abs($num1) > abs($num2) +     * +     * @param string $num1 +     * @param string $num2 +     * @return int +     * @access public +     */ +    function cmpAbs($num1, $num2) +    { +        return bccomp($num1, $num2); +    } + +    /** +     * Tests $num on primality. Returns true, if $num is strong pseudoprime. +     * Else returns false. +     * +     * @param string $num +     * @return bool +     * @access private +     */ +    function isPrime($num) +    { +        static $primes = null; +        static $primes_cnt = 0; +        if (is_null($primes)) { +            // generate all primes up to 10000 +            $primes = array(); +            for ($i = 0; $i < 10000; $i++) { +                $primes[] = $i; +            } +            $primes[0] = $primes[1] = 0; +            for ($i = 2; $i < 100; $i++) { +                while (!$primes[$i]) { +                    $i++; +                } +                $j = $i; +                for ($j += $i; $j < 10000; $j += $i) { +                    $primes[$j] = 0; +                } +            } +            $j = 0; +            for ($i = 0; $i < 10000; $i++) { +                if ($primes[$i]) { +                    $primes[$j++] = $primes[$i]; +                } +            } +            $primes_cnt = $j; +        } + +        // try to divide number by small primes +        for ($i = 0; $i < $primes_cnt; $i++) { +            if (bccomp($num, $primes[$i]) <= 0) { +                // number is prime +                return true; +            } +            if (!bccomp(bcmod($num, $primes[$i]), '0')) { +                // number divides by $primes[$i] +                return false; +            } +        } + +        /* +            try Miller-Rabin's probable-primality test for first +            7 primes as bases +        */ +        for ($i = 0; $i < 7; $i++) { +            if (!$this->_millerTest($num, $primes[$i])) { +                // $num is composite +                return false; +            } +        } +        // $num is strong pseudoprime +        return true; +    } + +    /** +     * Generates prime number with length $bits_cnt +     * using $random_generator as random generator function. +     * +     * @param int $bits_cnt +     * @param string $rnd_generator +     * @access public +     */ +    function getPrime($bits_cnt, $random_generator) +    { +        $bytes_n = intval($bits_cnt / 8); +        $bits_n = $bits_cnt % 8; +        do { +            $str = ''; +            for ($i = 0; $i < $bytes_n; $i++) { +                $str .= chr(call_user_func($random_generator) & 0xff); +            } +            $n = call_user_func($random_generator) & 0xff; +            $n |= 0x80; +            $n >>= 8 - $bits_n; +            $str .= chr($n); +            $num = $this->bin2int($str); + +            // search for the next closest prime number after [$num] +            if (!bccomp(bcmod($num, '2'), '0')) { +                $num = bcadd($num, '1'); +            } +            while (!$this->isPrime($num)) { +                $num = bcadd($num, '2'); +            } +        } while ($this->bitLen($num) != $bits_cnt); +        return $num; +    } + +    /** +     * Calculates $num - 1 +     * +     * @param string $num +     * @return string +     * @access public +     */ +    function dec($num) +    { +        return bcsub($num, '1'); +    } + +    /** +     * Returns true, if $num is equal to one. Else returns false +     * +     * @param string $num +     * @return bool +     * @access public +     */ +    function isOne($num) +    { +        return !bccomp($num, '1'); +    } + +    /** +     * Finds greatest common divider (GCD) of $num1 and $num2 +     * +     * @param string $num1 +     * @param string $num2 +     * @return string +     * @access public +     */ +    function GCD($num1, $num2) +    { +        do { +            $tmp = bcmod($num1, $num2); +            $num1 = $num2; +            $num2 = $tmp; +        } while (bccomp($num2, '0')); +        return $num1; +    } + +    /** +     * Finds inverse number $inv for $num by modulus $mod, such as: +     *     $inv * $num = 1 (mod $mod) +     * +     * @param string $num +     * @param string $mod +     * @return string +     * @access public +     */ +    function invmod($num, $mod) +    { +        $x = '1'; +        $y = '0'; +        $num1 = $mod; +        do { +            $tmp = bcmod($num, $num1); +            $q = bcdiv($num, $num1); +            $num = $num1; +            $num1 = $tmp; + +            $tmp = bcsub($x, bcmul($y, $q)); +            $x = $y; +            $y = $tmp; +        } while (bccomp($num1, '0')); +        if (bccomp($x, '0') < 0) { +            $x = bcadd($x, $mod); +        } +        return $x; +    } + +    /** +     * Returns bit length of number $num +     * +     * @param string $num +     * @return int +     * @access public +     */ +    function bitLen($num) +    { +        $tmp = $this->int2bin($num); +        $bit_len = strlen($tmp) * 8; +        $tmp = ord($tmp{strlen($tmp) - 1}); +        if (!$tmp) { +            $bit_len -= 8; +        } +        else { +            while (!($tmp & 0x80)) { +                $bit_len--; +                $tmp <<= 1; +            } +        } +        return $bit_len; +    } + +    /** +     * Calculates bitwise or of $num1 and $num2, +     * starting from bit $start_pos for number $num1 +     * +     * @param string $num1 +     * @param string $num2 +     * @param int $start_pos +     * @return string +     * @access public +     */ +    function bitOr($num1, $num2, $start_pos) +    { +        $start_byte = intval($start_pos / 8); +        $start_bit = $start_pos % 8; +        $tmp1 = $this->int2bin($num1); + +        $num2 = bcmul($num2, 1 << $start_bit); +        $tmp2 = $this->int2bin($num2); +        if ($start_byte < strlen($tmp1)) { +            $tmp2 |= substr($tmp1, $start_byte); +            $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2; +        } +        else { +            $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2; +        } +        return $this->bin2int($tmp1); +    } + +    /** +     * Returns part of number $num, starting at bit +     * position $start with length $length +     * +     * @param string $num +     * @param int start +     * @param int length +     * @return string +     * @access public +     */ +    function subint($num, $start, $length) +    { +        $start_byte = intval($start / 8); +        $start_bit = $start % 8; +        $byte_length = intval($length / 8); +        $bit_length = $length % 8; +        if ($bit_length) { +            $byte_length++; +        } +        $num = bcdiv($num, 1 << $start_bit); +        $tmp = substr($this->int2bin($num), $start_byte, $byte_length); +        $tmp = str_pad($tmp, $byte_length, "\0"); +        $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1); +        return $this->bin2int($tmp); +    } + +    /** +     * Returns name of current wrapper +     * +     * @return string name of current wrapper +     * @access public +     */ +    function getWrapperName() +    { +        return 'BCMath'; +    } +} + +?>
\ No newline at end of file diff --git a/mod/openid_server/Crypt/RSA/Math/BigInt.php b/mod/openid_server/Crypt/RSA/Math/BigInt.php new file mode 100644 index 000000000..b7ac24cb6 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/Math/BigInt.php @@ -0,0 +1,313 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version    1.2.0b + * @link       http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_BigInt class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for big_int PECL extension, + * which could be loaded from http://pecl.php.net/packages/big_int + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @link       http://pear.php.net/package/Crypt_RSA + * @version    @package_version@ + * @access     public + */ +class Crypt_RSA_Math_BigInt +{ +    /** +     * error description +     * +     * @var string +     * @access public +     */ +    var $errstr = ''; + +    /** +     * Crypt_RSA_Math_BigInt constructor. +     * Checks an existance of big_int PECL math package. +     * This package is available at http://pecl.php.net/packages/big_int +     * On failure saves error description in $this->errstr +     * +     * @access public +     */ +    function Crypt_RSA_Math_BigInt() +    { +        if (!extension_loaded('big_int')) { +            if (!@dl('big_int.' . PHP_SHLIB_SUFFIX) && !@dl('php_big_int.' . PHP_SHLIB_SUFFIX)) { +                // cannot load big_int extension +                $this->errstr = 'Crypt_RSA package requires big_int PECL package. ' . +                     'It is available at http://pecl.php.net/packages/big_int'; +                return; +            } +        } + +        // check version of big_int extension ( Crypt_RSA requires version 1.0.2 and higher ) +        if (!in_array('bi_info', get_extension_funcs('big_int'))) { +            // there is no bi_info() function in versions, older than 1.0.2 +            $this->errstr = 'Crypt_RSA package requires big_int package version 1.0.2 and higher'; +        } +    } + +    /** +     * Transforms binary representation of large integer into its native form. +     *  +     * Example of transformation: +     *    $str = "\x12\x34\x56\x78\x90"; +     *    $num = 0x9078563412; +     * +     * @param string $str +     * @return big_int resource +     * @access public +     */ +    function bin2int($str) +    { +        return bi_unserialize($str); +    } + +    /** +     * Transforms large integer into binary representation. +     *  +     * Example of transformation: +     *    $num = 0x9078563412; +     *    $str = "\x12\x34\x56\x78\x90"; +     * +     * @param big_int resource $num +     * @return string +     * @access public +     */ +    function int2bin($num) +    { +        return bi_serialize($num); +    } + +    /** +     * Calculates pow($num, $pow) (mod $mod) +     * +     * @param big_int resource $num +     * @param big_int resource $pow +     * @param big_int resource $mod +     * @return big_int resource +     * @access public +     */ +    function powmod($num, $pow, $mod) +    { +        return bi_powmod($num, $pow, $mod); +    } + +    /** +     * Calculates $num1 * $num2 +     * +     * @param big_int resource $num1 +     * @param big_int resource $num2 +     * @return big_int resource +     * @access public +     */ +    function mul($num1, $num2) +    { +        return bi_mul($num1, $num2); +    } + +    /** +     * Calculates $num1 % $num2 +     * +     * @param string $num1 +     * @param string $num2 +     * @return string +     * @access public +     */ +    function mod($num1, $num2) +    { +        return bi_mod($num1, $num2); +    } + +    /** +     * Compares abs($num1) to abs($num2). +     * Returns: +     *   -1, if abs($num1) < abs($num2) +     *   0, if abs($num1) == abs($num2) +     *   1, if abs($num1) > abs($num2) +     * +     * @param big_int resource $num1 +     * @param big_int resource $num2 +     * @return int +     * @access public +     */ +    function cmpAbs($num1, $num2) +    { +        return bi_cmp_abs($num1, $num2); +    } + +    /** +     * Tests $num on primality. Returns true, if $num is strong pseudoprime. +     * Else returns false. +     * +     * @param string $num +     * @return bool +     * @access private +     */ +    function isPrime($num) +    { +        return bi_is_prime($num) ? true : false; +    } + +    /** +     * Generates prime number with length $bits_cnt +     * using $random_generator as random generator function. +     * +     * @param int $bits_cnt +     * @param string $rnd_generator +     * @access public +     */ +    function getPrime($bits_cnt, $random_generator) +    { +        $bytes_n = intval($bits_cnt / 8); +        $bits_n = $bits_cnt % 8; +        do { +            $str = ''; +            for ($i = 0; $i < $bytes_n; $i++) { +                $str .= chr(call_user_func($random_generator) & 0xff); +            } +            $n = call_user_func($random_generator) & 0xff; +            $n |= 0x80; +            $n >>= 8 - $bits_n; +            $str .= chr($n); +            $num = $this->bin2int($str); + +            // search for the next closest prime number after [$num] +            $num = bi_next_prime($num); +        } while ($this->bitLen($num) != $bits_cnt); +        return $num; +    } + +    /** +     * Calculates $num - 1 +     * +     * @param big_int resource $num +     * @return big_int resource +     * @access public +     */ +    function dec($num) +    { +        return bi_dec($num); +    } + +    /** +     * Returns true, if $num is equal to 1. Else returns false +     * +     * @param big_int resource $num +     * @return bool +     * @access public +     */ +    function isOne($num) +    { +        return bi_is_one($num); +    } + +    /** +     * Finds greatest common divider (GCD) of $num1 and $num2 +     * +     * @param big_int resource $num1 +     * @param big_int resource $num2 +     * @return big_int resource +     * @access public +     */ +    function GCD($num1, $num2) +    { +        return bi_gcd($num1, $num2); +    } + +    /** +     * Finds inverse number $inv for $num by modulus $mod, such as: +     *     $inv * $num = 1 (mod $mod) +     * +     * @param big_int resource $num +     * @param big_int resource $mod +     * @return big_int resource +     * @access public +     */ +    function invmod($num, $mod) +    { +        return bi_invmod($num, $mod); +    } + +    /** +     * Returns bit length of number $num +     * +     * @param big_int resource $num +     * @return int +     * @access public +     */ +    function bitLen($num) +    { +        return bi_bit_len($num); +    } + +    /** +     * Calculates bitwise or of $num1 and $num2, +     * starting from bit $start_pos for number $num1 +     * +     * @param big_int resource $num1 +     * @param big_int resource $num2 +     * @param int $start_pos +     * @return big_int resource +     * @access public +     */ +    function bitOr($num1, $num2, $start_pos) +    { +        return bi_or($num1, $num2, $start_pos); +    } + +    /** +     * Returns part of number $num, starting at bit +     * position $start with length $length +     * +     * @param big_int resource $num +     * @param int start +     * @param int length +     * @return big_int resource +     * @access public +     */ +    function subint($num, $start, $length) +    { +        return bi_subint($num, $start, $length); +    } + +    /** +     * Returns name of current wrapper +     * +     * @return string name of current wrapper +     * @access public +     */ +    function getWrapperName() +    { +        return 'BigInt'; +    } +} + +?>
\ No newline at end of file diff --git a/mod/openid_server/Crypt/RSA/Math/GMP.php b/mod/openid_server/Crypt/RSA/Math/GMP.php new file mode 100644 index 000000000..54e4c34fc --- /dev/null +++ b/mod/openid_server/Crypt/RSA/Math/GMP.php @@ -0,0 +1,361 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version    1.2.0b + * @link       http://pear.php.net/package/Crypt_RSA + */ + +/** + * Crypt_RSA_Math_GMP class. + * + * Provides set of math functions, which are used by Crypt_RSA package + * This class is a wrapper for PHP GMP extension. + * See http://php.net/gmp for details. + * + * @category   Encryption + * @package    Crypt_RSA + * @author     Alexander Valyalkin <valyala@gmail.com> + * @copyright  2005, 2006 Alexander Valyalkin + * @license    http://www.php.net/license/3_0.txt  PHP License 3.0 + * @link       http://pear.php.net/package/Crypt_RSA + * @version    @package_version@ + * @access     public + */ +class Crypt_RSA_Math_GMP +{ +    /** +     * error description +     * +     * @var string +     * @access public +     */ +    var $errstr = ''; + +    /** +     * Crypt_RSA_Math_GMP constructor. +     * Checks an existance of PHP GMP package. +     * See http://php.net/gmp for details. +     * +     * On failure saves error description in $this->errstr +     * +     * @access public +     */ +    function Crypt_RSA_Math_GMP() +    { +        if (!extension_loaded('gmp')) { +            if (!@dl('gmp.' . PHP_SHLIB_SUFFIX) && !@dl('php_gmp.' . PHP_SHLIB_SUFFIX)) { +                // cannot load GMP extension +                $this->errstr = 'Crypt_RSA package requires PHP GMP package. ' . +                     'See http://php.net/gmp for details'; +                return; +            } +        } +    } + +    /** +     * Transforms binary representation of large integer into its native form. +     *  +     * Example of transformation: +     *    $str = "\x12\x34\x56\x78\x90"; +     *    $num = 0x9078563412; +     * +     * @param string $str +     * @return gmp resource +     * @access public +     */ +    function bin2int($str) +    { +        $result = 0; +        $n = strlen($str); +        do { +            // dirty hack: GMP returns FALSE, when second argument equals to int(0). +            // so, it must be converted to string '0' +            $result = gmp_add(gmp_mul($result, 256), strval(ord($str{--$n}))); +        } while ($n > 0); +        return $result; +    } + +    /** +     * Transforms large integer into binary representation. +     *  +     * Example of transformation: +     *    $num = 0x9078563412; +     *    $str = "\x12\x34\x56\x78\x90"; +     * +     * @param gmp resource $num +     * @return string +     * @access public +     */ +    function int2bin($num) +    { +        $result = ''; +        do { +            $result .= chr(gmp_intval(gmp_mod($num, 256))); +            $num = gmp_div($num, 256); +        } while (gmp_cmp($num, 0)); +        return $result; +    } + +    /** +     * Calculates pow($num, $pow) (mod $mod) +     * +     * @param gmp resource $num +     * @param gmp resource $pow +     * @param gmp resource $mod +     * @return gmp resource +     * @access public +     */ +    function powmod($num, $pow, $mod) +    { +        return gmp_powm($num, $pow, $mod); +    } + +    /** +     * Calculates $num1 * $num2 +     * +     * @param gmp resource $num1 +     * @param gmp resource $num2 +     * @return gmp resource +     * @access public +     */ +    function mul($num1, $num2) +    { +        return gmp_mul($num1, $num2); +    } + +    /** +     * Calculates $num1 % $num2 +     * +     * @param string $num1 +     * @param string $num2 +     * @return string +     * @access public +     */ +    function mod($num1, $num2) +    { +        return gmp_mod($num1, $num2); +    } + +    /** +     * Compares abs($num1) to abs($num2). +     * Returns: +     *   -1, if abs($num1) < abs($num2) +     *   0, if abs($num1) == abs($num2) +     *   1, if abs($num1) > abs($num2) +     * +     * @param gmp resource $num1 +     * @param gmp resource $num2 +     * @return int +     * @access public +     */ +    function cmpAbs($num1, $num2) +    { +        return gmp_cmp($num1, $num2); +    } + +    /** +     * Tests $num on primality. Returns true, if $num is strong pseudoprime. +     * Else returns false. +     * +     * @param string $num +     * @return bool +     * @access private +     */ +    function isPrime($num) +    { +        return gmp_prob_prime($num) ? true : false; +    } + +    /** +     * Generates prime number with length $bits_cnt +     * using $random_generator as random generator function. +     * +     * @param int $bits_cnt +     * @param string $rnd_generator +     * @access public +     */ +    function getPrime($bits_cnt, $random_generator) +    { +        $bytes_n = intval($bits_cnt / 8); +        $bits_n = $bits_cnt % 8; +        do { +            $str = ''; +            for ($i = 0; $i < $bytes_n; $i++) { +                $str .= chr(call_user_func($random_generator) & 0xff); +            } +            $n = call_user_func($random_generator) & 0xff; +            $n |= 0x80; +            $n >>= 8 - $bits_n; +            $str .= chr($n); +            $num = $this->bin2int($str); + +            // search for the next closest prime number after [$num] +            if (!gmp_cmp(gmp_mod($num, '2'), '0')) { +                $num = gmp_add($num, '1'); +            } +            while (!gmp_prob_prime($num)) { +                $num = gmp_add($num, '2'); +            } +        } while ($this->bitLen($num) != $bits_cnt); +        return $num; +    } + +    /** +     * Calculates $num - 1 +     * +     * @param gmp resource $num +     * @return gmp resource +     * @access public +     */ +    function dec($num) +    { +        return gmp_sub($num, 1); +    } + +    /** +     * Returns true, if $num is equal to one. Else returns false +     * +     * @param gmp resource $num +     * @return bool +     * @access public +     */ +    function isOne($num) +    { +        return !gmp_cmp($num, 1); +    } + +    /** +     * Finds greatest common divider (GCD) of $num1 and $num2 +     * +     * @param gmp resource $num1 +     * @param gmp resource $num2 +     * @return gmp resource +     * @access public +     */ +    function GCD($num1, $num2) +    { +        return gmp_gcd($num1, $num2); +    } + +    /** +     * Finds inverse number $inv for $num by modulus $mod, such as: +     *     $inv * $num = 1 (mod $mod) +     * +     * @param gmp resource $num +     * @param gmp resource $mod +     * @return gmp resource +     * @access public +     */ +    function invmod($num, $mod) +    { +        return gmp_invert($num, $mod); +    } + +    /** +     * Returns bit length of number $num +     * +     * @param gmp resource $num +     * @return int +     * @access public +     */ +    function bitLen($num) +    { +        $tmp = $this->int2bin($num); +        $bit_len = strlen($tmp) * 8; +        $tmp = ord($tmp{strlen($tmp) - 1}); +        if (!$tmp) { +            $bit_len -= 8; +        } +        else { +            while (!($tmp & 0x80)) { +                $bit_len--; +                $tmp <<= 1; +            } +        } +        return $bit_len; +    } + +    /** +     * Calculates bitwise or of $num1 and $num2, +     * starting from bit $start_pos for number $num1 +     * +     * @param gmp resource $num1 +     * @param gmp resource $num2 +     * @param int $start_pos +     * @return gmp resource +     * @access public +     */ +    function bitOr($num1, $num2, $start_pos) +    { +        $start_byte = intval($start_pos / 8); +        $start_bit = $start_pos % 8; +        $tmp1 = $this->int2bin($num1); + +        $num2 = gmp_mul($num2, 1 << $start_bit); +        $tmp2 = $this->int2bin($num2); +        if ($start_byte < strlen($tmp1)) { +            $tmp2 |= substr($tmp1, $start_byte); +            $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2; +        } +        else { +            $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2; +        } +        return $this->bin2int($tmp1); +    } + +    /** +     * Returns part of number $num, starting at bit +     * position $start with length $length +     * +     * @param gmp resource $num +     * @param int start +     * @param int length +     * @return gmp resource +     * @access public +     */ +    function subint($num, $start, $length) +    { +        $start_byte = intval($start / 8); +        $start_bit = $start % 8; +        $byte_length = intval($length / 8); +        $bit_length = $length % 8; +        if ($bit_length) { +            $byte_length++; +        } +        $num = gmp_div($num, 1 << $start_bit); +        $tmp = substr($this->int2bin($num), $start_byte, $byte_length); +        $tmp = str_pad($tmp, $byte_length, "\0"); +        $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1); +        return $this->bin2int($tmp); +    } + +    /** +     * Returns name of current wrapper +     * +     * @return string name of current wrapper +     * @access public +     */ +    function getWrapperName() +    { +        return 'GMP'; +    } +} + +?>
\ No newline at end of file diff --git a/mod/openid_server/Crypt/RSA/MathLoader.php b/mod/openid_server/Crypt/RSA/MathLoader.php new file mode 100644 index 000000000..de6c94642 --- /dev/null +++ b/mod/openid_server/Crypt/RSA/MathLoader.php @@ -0,0 +1,135 @@ +<?php +/** + * Crypt_RSA allows to do following operations: + *     - key pair generation + *     - encryption and decryption + *     - signing and sign validation + * + * PHP versions 4 and 5 + * + * LICENSE: This source file is subject to version 3.0 of the PHP license + * that is available through the world-wide-web at the following URI: + * http://www.php.net/license/3_0.txt.  If you did not receive a copy of + * the PHP License and are unable to obtain it through the web, please + * send a note to license@php.net so we can mail you a copy immediately. + * + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright Alexander Valyalkin 2005 + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   CVS: $Id: MathLoader.php,v 1.5 2009/01/05 08:30:29 clockwerx Exp $ + * @link      http://pear.php.net/package/Crypt_RSA + */ + +/** + * RSA error handling facilities + */ +require_once 'Crypt/RSA/ErrorHandler.php'; + +/** + * Crypt_RSA_MathLoader class. + * + * Provides static function: + *  - loadWrapper($wrapper_name) - loads RSA math wrapper with name $wrapper_name + *                                 or most suitable wrapper if $wrapper_name == 'default' + * + * Example usage: + *    // load BigInt wrapper + *    $big_int_wrapper = Crypt_RSA_MathLoader::loadWrapper('BigInt'); + *  + *    // load BCMath wrapper + *    $bcmath_wrapper = Crypt_RSA_MathLoader::loadWrapper('BCMath'); + *  + *    // load the most suitable wrapper + *    $bcmath_wrapper = Crypt_RSA_MathLoader::loadWrapper(); + *  + * @category  Encryption + * @package   Crypt_RSA + * @author    Alexander Valyalkin <valyala@gmail.com> + * @copyright Alexander Valyalkin 2005 + * @license   http://www.php.net/license/3_0.txt  PHP License 3.0 + * @version   Release: @package_version@ + * @link      http://pear.php.net/package/Crypt_RSA + * @access    public + */ +class Crypt_RSA_MathLoader +{ +    /** +     * Loads RSA math wrapper with name $wrapper_name. +     * Implemented wrappers can be found at Crypt/RSA/Math folder. +     * Read docs/Crypt_RSA/docs/math_wrappers.txt for details +     * +     * This is a static function: +     *    // load BigInt wrapper +     *    $big_int_wrapper = &Crypt_RSA_MathLoader::loadWrapper('BigInt'); +     * +     *    // load BCMath wrapper +     *    $bcmath_wrapper = &Crypt_RSA_MathLoader::loadWrapper('BCMath'); +     * +     * @param string $wrapper_name Name of wrapper +     * +     * @return object +     *         Reference to object of wrapper with name $wrapper_name on success +     *         or PEAR_Error object on error +     * +     * @access public +     */ +    function loadWrapper($wrapper_name = 'default') +    { +        static $math_objects = array(); +        // ordered by performance. GMP is the fastest math library, BCMath - the slowest. +        static $math_wrappers = array('GMP', 'BigInt', 'BCMath',); + +        if (isset($math_objects[$wrapper_name])) { +            /* +                wrapper with name $wrapper_name is already loaded and created. +                Return reference to existing copy of wrapper +            */ +            return $math_objects[$wrapper_name]; +        } + +        $err_handler = new Crypt_RSA_ErrorHandler(); + +        if ($wrapper_name === 'default') { +            // try to load the most suitable wrapper +            $n = sizeof($math_wrappers); +            for ($i = 0; $i < $n; $i++) { +                $obj = Crypt_RSA_MathLoader::loadWrapper($math_wrappers[$i]); +                if (!$err_handler->isError($obj)) { +                    // wrapper for $math_wrappers[$i] successfully loaded +                    // register it as default wrapper and return reference to it +                    return $math_objects['default'] = $obj; +                } +            } +            // can't load any wrapper +            $err_handler->pushError("can't load any wrapper for existing math libraries", CRYPT_RSA_ERROR_NO_WRAPPERS); +            return $err_handler->getLastError(); +        } + +        $class_name = 'Crypt_RSA_Math_' . $wrapper_name; +        $class_filename = dirname(__FILE__) . '/Math/' . $wrapper_name . '.php'; + +        if (!is_file($class_filename)) { +            $err_handler->pushError("can't find file [{$class_filename}] for RSA math wrapper [{$wrapper_name}]", CRYPT_RSA_ERROR_NO_FILE); +            return $err_handler->getLastError(); +        } + +        include_once $class_filename; +        if (!class_exists($class_name)) { +            $err_handler->pushError("can't find class [{$class_name}] in file [{$class_filename}]", CRYPT_RSA_ERROR_NO_CLASS); +            return $err_handler->getLastError(); +        } + +        // create and return wrapper object on success or PEAR_Error object on error +        $obj = new $class_name; +        if ($obj->errstr) { +            // cannot load required extension for math wrapper +            $err_handler->pushError($obj->errstr, CRYPT_RSA_ERROR_NO_EXT); +            return $err_handler->getLastError(); +        } +        return $math_objects[$wrapper_name] = $obj; +    } +} + +?>  | 
