/** * Execute the console command. * * @return mixed */ public function handle() { $maxInt = 2147483647; $min = new BigInteger(10000000.0); $max = new BigInteger($maxInt); $prime = $max->randomPrime($min, $max); $a = new BigInteger($prime); $b = new BigInteger($maxInt + 1); if (!($inverse = $a->modInverse($b))) { $this->error("An error accured during calculation. Please re-run 'php artisan rocid:generate'."); return; } $random = hexdec(bin2hex(Random::string(4))) & $maxInt; $this->info("Generated numbers (Paste these in config/rockid.php) :\nprime: {$prime}\ninverse: {$inverse}\nrandom: {$random}"); }
protected function execute(InputInterface $input, OutputInterface $output) { $prime = $input->getArgument('prime'); // Get a pseudo-random prime. if (!$prime) { $min = new BigInteger(10000000.0); $max = new BigInteger(Optimus::MAX_INT); $prime = $max->randomPrime($min, $max); } // Calculate the inverse. $a = new BigInteger($prime); $b = new BigInteger(Optimus::MAX_INT + 1); if (!($inverse = $a->modInverse($b))) { $output->writeln('<error>Invalid prime number</>'); return; } $rand = hexdec(bin2hex(Random::string(4))) & Optimus::MAX_INT; $output->writeln('Prime: ' . $prime); $output->writeln('Inverse: ' . $inverse); $output->writeln('Random: ' . $rand); $output->writeln(''); $output->writeln(' new Optimus(' . $prime . ', ' . $inverse . ', ' . $rand . ');'); }
/** * Create public / private key pair * * Returns an array with the following three elements: * - 'privatekey': The private key. * - 'publickey': The public key. * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). * Will need to be passed back to RSA::createKey() as the third parameter for further processing. * * @access public * @param * optional Integer $bits * @param * optional Integer $timeout * @param * optional BigInteger $p */ function createKey($bits = 1024, $timeout = false, $partial = array()) { if (!defined('CRYPT_RSA_EXPONENT')) { // http://en.wikipedia.org/wiki/65537_%28number%29 @define('CRYPT_RSA_EXPONENT', '65537'); } // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key // generation when there's a chance neither gmp nor OpenSSL are installed) if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { @define('CRYPT_RSA_SMALLEST_PRIME', 4096); } // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { $config = array(); if (isset($this->configFile)) { $config['config'] = $this->configFile; } $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config); openssl_pkey_export($rsa, $privatekey, null, $config); $publickey = openssl_pkey_get_details($rsa); $publickey = $publickey['key']; $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); // clear the buffer of error strings stemming from a minimalistic openssl.cnf while (openssl_error_string() !== false) { } return array('privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false); } static $e; if (!isset($e)) { $e = new BigInteger(CRYPT_RSA_EXPONENT); } extract($this->_generateMinMax($bits)); $absoluteMin = $min; $temp = $bits >> 1; // divide by two to see how many bits P and Q would be if ($temp > CRYPT_RSA_SMALLEST_PRIME) { $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); $temp = CRYPT_RSA_SMALLEST_PRIME; } else { $num_primes = 2; } extract($this->_generateMinMax($temp + $bits % $temp)); $finalMax = $max; extract($this->_generateMinMax($temp)); $generator = new BigInteger(); $n = $this->one->copy(); if (!empty($partial)) { extract(unserialize($partial)); } else { $exponents = $coefficients = $primes = array(); $lcm = array('top' => $this->one->copy(), 'bottom' => false); } $start = time(); $i0 = count($primes) + 1; do { for ($i = $i0; $i <= $num_primes; $i++) { if ($timeout !== false) { $timeout -= time() - $start; $start = time(); if ($timeout <= 0) { return array('privatekey' => '', 'publickey' => '', 'partialkey' => serialize(array('primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents))); } } if ($i == $num_primes) { list($min, $temp) = $absoluteMin->divide($n); if (!$temp->equals($this->zero)) { $min = $min->add($this->one); // ie. ceil() } $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); } else { $primes[$i] = $generator->randomPrime($min, $max, $timeout); } if ($primes[$i] === false) { // if we've reached the timeout if (count($primes) > 1) { $partialkey = ''; } else { array_pop($primes); $partialkey = serialize(array('primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents)); } return array('privatekey' => '', 'publickey' => '', 'partialkey' => $partialkey); } // the first coefficient is calculated differently from the rest // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract($this->one); // textbook RSA implementations use Euler's totient function instead of the least common multiple. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); $exponents[$i] = $e->modInverse($temp); } list($temp) = $lcm['top']->divide($lcm['bottom']); $gcd = $temp->gcd($e); $i0 = 1; } while (!$gcd->equals($this->one)); $d = $e->modInverse($temp); $coefficients[2] = $primes[2]->modInverse($primes[1]); // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>: // RSAPrivateKey ::= SEQUENCE { // version Version, // modulus INTEGER, -- n // publicExponent INTEGER, -- e // privateExponent INTEGER, -- d // prime1 INTEGER, -- p // prime2 INTEGER, -- q // exponent1 INTEGER, -- d mod (p-1) // exponent2 INTEGER, -- d mod (q-1) // coefficient INTEGER, -- (inverse of q) mod p // otherPrimeInfos OtherPrimeInfos OPTIONAL // } return array('privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients), 'publickey' => $this->_convertPublicKey($n, $e), 'partialkey' => false); }
/** * Generate a random large prime. * * @return int */ public static function generatePrime() { $min = new BigInteger(10000000.0); $max = new BigInteger(Optimus::MAX_INT); return (int) $max->randomPrime($min, $max)->toString(); }
/** * Create public / private key pair * * Returns an array with the following three elements: * - 'privatekey': The private key. * - 'publickey': The public key. * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). * Will need to be passed back to \phpseclib\Crypt\RSA::createKey() as the third parameter for further processing. * * @access public * @param int $bits * @param int $timeout * @param array $p */ static function createKey($bits = 2048, $timeout = false, $partial = array()) { self::_initialize_static_variables(); if (!defined('CRYPT_RSA_MODE')) { switch (true) { // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'): define('CRYPT_RSA_MODE', self::MODE_INTERNAL); break; case extension_loaded('openssl') && file_exists(self::$configFile): // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work ob_start(); @phpinfo(); $content = ob_get_contents(); ob_end_clean(); preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches); $versions = array(); if (!empty($matches[1])) { for ($i = 0; $i < count($matches[1]); $i++) { $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); // Remove letter part in OpenSSL version if (!preg_match('/(\\d+\\.\\d+\\.\\d+)/i', $fullVersion, $m)) { $versions[$matches[1][$i]] = $fullVersion; } else { $versions[$matches[1][$i]] = $m[0]; } } } // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+ switch (true) { case !isset($versions['Header']): case !isset($versions['Library']): case $versions['Header'] == $versions['Library']: define('CRYPT_RSA_MODE', self::MODE_OPENSSL); break; default: define('CRYPT_RSA_MODE', self::MODE_INTERNAL); define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); } break; default: define('CRYPT_RSA_MODE', self::MODE_INTERNAL); } } if (!defined('CRYPT_RSA_EXPONENT')) { // http://en.wikipedia.org/wiki/65537_%28number%29 define('CRYPT_RSA_EXPONENT', '65537'); } // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if // CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key // generation when there's a chance neither gmp nor OpenSSL are installed) if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { define('CRYPT_RSA_SMALLEST_PRIME', 4096); } // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) { $config = array(); if (isset(self::$configFile)) { $config['config'] = self::$configFile; } $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config); openssl_pkey_export($rsa, $privatekeystr, null, $config); $privatekey = new RSA(); $privatekey->load($privatekeystr); $publickeyarr = openssl_pkey_get_details($rsa); $publickey = new RSA(); $publickey->load($publickeyarr['key']); // clear the buffer of error strings stemming from a minimalistic openssl.cnf while (openssl_error_string() !== false) { } return array('privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false); } static $e; if (!isset($e)) { $e = new BigInteger(CRYPT_RSA_EXPONENT); } extract(self::_generateMinMax($bits)); $absoluteMin = $min; $temp = $bits >> 1; // divide by two to see how many bits P and Q would be if ($temp > CRYPT_RSA_SMALLEST_PRIME) { $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); $temp = CRYPT_RSA_SMALLEST_PRIME; } else { $num_primes = 2; } extract(self::_generateMinMax($temp + $bits % $temp)); $finalMax = $max; extract(self::_generateMinMax($temp)); $n = clone self::$one; if (!empty($partial)) { extract(unserialize($partial)); } else { $exponents = $coefficients = $primes = array(); $lcm = array('top' => clone self::$one, 'bottom' => false); } $start = time(); $i0 = count($primes) + 1; do { for ($i = $i0; $i <= $num_primes; $i++) { if ($timeout !== false) { $timeout -= time() - $start; $start = time(); if ($timeout <= 0) { return array('privatekey' => '', 'publickey' => '', 'partialkey' => serialize(array('primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents))); } } if ($i == $num_primes) { list($min, $temp) = $absoluteMin->divide($n); if (!$temp->equals(self::$zero)) { $min = $min->add(self::$one); // ie. ceil() } $primes[$i] = BigInteger::randomPrime($min, $finalMax, $timeout); } else { $primes[$i] = BigInteger::randomPrime($min, $max, $timeout); } if ($primes[$i] === false) { // if we've reached the timeout if (count($primes) > 1) { $partialkey = ''; } else { array_pop($primes); $partialkey = serialize(array('primes' => $primes, 'coefficients' => $coefficients, 'lcm' => $lcm, 'exponents' => $exponents)); } return array('privatekey' => false, 'publickey' => false, 'partialkey' => $partialkey); } // the first coefficient is calculated differently from the rest // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) if ($i > 2) { $coefficients[$i] = $n->modInverse($primes[$i]); } $n = $n->multiply($primes[$i]); $temp = $primes[$i]->subtract(self::$one); // textbook RSA implementations use Euler's totient function instead of the least common multiple. // see http://en.wikipedia.org/wiki/Euler%27s_totient_function $lcm['top'] = $lcm['top']->multiply($temp); $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); $exponents[$i] = $e->modInverse($temp); } list($temp) = $lcm['top']->divide($lcm['bottom']); $gcd = $temp->gcd($e); $i0 = 1; } while (!$gcd->equals(self::$one)); $d = $e->modInverse($temp); $coefficients[2] = $primes[2]->modInverse($primes[1]); // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>: // RSAPrivateKey ::= SEQUENCE { // version Version, // modulus INTEGER, -- n // publicExponent INTEGER, -- e // privateExponent INTEGER, -- d // prime1 INTEGER, -- p // prime2 INTEGER, -- q // exponent1 INTEGER, -- d mod (p-1) // exponent2 INTEGER, -- d mod (q-1) // coefficient INTEGER, -- (inverse of q) mod p // otherPrimeInfos OtherPrimeInfos OPTIONAL // } $privatekey = new RSA(); $privatekey->modulus = $n; $privatekey->k = $bits >> 3; $privatekey->publicExponent = $e; $privatekey->exponent = $d; $privatekey->privateExponent = $e; $privatekey->primes = $primes; $privatekey->exponents = $exponents; $privatekey->coefficients = $coefficients; $publickey = new RSA(); $publickey->modulus = $n; $publickey->k = $bits >> 3; $publickey->exponent = $e; return array('privatekey' => $privatekey, 'publickey' => $publickey, 'partialkey' => false); }