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(""); // 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' => "", '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 }
/** * 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 * 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. * * @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') { $obj = new Crypt_RSA_Key($modulus, $exp, $key_type, $wrapper_name); if ($obj->isError()) { // error during creating a new object. Retrurn 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)) { $obj = PEAR::raiseError('missing key_len parameter', CRYPT_RSA_ERROR_MISSING_KEY_LEN); $this->pushError($obj); return false; } } // align $key_len to 8 bits if ($key_len & 7) { $key_len += 8 - $key_len % 8; } // store key length in the _key_len property $this->_key_len = $key_len; // generate two primes p and q $p_len = (int) ($key_len / 2) + 1; $q_len = $key_len - $p_len; $p = $this->_math_obj->getRand($p_len, $this->_random_generator, true); $p = $this->_math_obj->nextPrime($p); do { do { $q = $this->_math_obj->getRand($q_len, $this->_random_generator, true); $tmp_len = $this->_math_obj->bitLen($this->_math_obj->mul($p, $q)); if ($tmp_len < $key_len) { $q_len++; } elseif ($tmp_len > $key_len) { $q_len--; } } while ($tmp_len != $key_len); $q = $this->_math_obj->nextPrime($q); $tmp = $this->_math_obj->mul($p, $q); } while ($this->_math_obj->bitLen($tmp) != $key_len); // $n - is shared modulus $n = $this->_math_obj->mul($p, $q); // generate public ($e) and private ($d) keys $pq = $this->_math_obj->mul($this->_math_obj->dec($p), $this->_math_obj->dec($q)); do { $e = $this->_math_obj->getRand($q_len, $this->_random_generator); if ($this->_math_obj->isZero($e) || $this->_math_obj->isZero($this->_math_obj->dec($e))) { // exponent cannot be equal to 0 or 1 continue; } if ($this->_math_obj->isZero($this->_math_obj->dec($this->_math_obj->gcd($e, $pq)))) { // exponent is found break; } } while (true); $d = $this->_math_obj->invmod($e, $pq); $modulus = $this->_math_obj->int2bin($n); $public_exp = $this->_math_obj->int2bin($e); $private_exp = $this->_math_obj->int2bin($d); // try to create public key object $obj = new Crypt_RSA_Key($modulus, $public_exp, '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($modulus, $private_exp, '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 }