Exemple #1
0
 /**
  * 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 CryptRSA::createKey() as the third parameter for further processing.
  *
  * @access public
  * @param optional Integer $bits
  * @param optional Integer $timeout
  * @param optional MathBigInteger $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) {
         $inst = Configuration::getInstance();
         $cnfPath = Utils::path_concat($inst->get('base_path'), $inst->get('var_path'), 'openssl.cnf');
         $rsa = openssl_pkey_new(array('private_key_bits' => $bits, 'config' => $cnfPath));
         openssl_pkey_export($rsa, $privatekey, NULL, array('config' => $cnfPath));
         $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 MathBigInteger(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 MathBigInteger();
     $generator->setRandomGenerator('crypt_random');
     $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($lcm) = $lcm['top']->divide($lcm['bottom']);
         $gcd = $lcm->gcd($e);
         $i0 = 1;
     } while (!$gcd->equals($this->one));
     $d = $e->modInverse($lcm);
     $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);
 }
Exemple #2
0
 /**
  * DSA verify
  *
  * @param string $message message
  * @param string $hash_alg hash algorithm
  * @param MathBigInteger $r r
  * @param MathBigInteger $s s
  * @param MathBigInteger $p p
  * @param MathBigInteger $q q
  * @param MathBigInteger $g g
  * @param MathBigInteger $y public key
  * @return bool
  */
 public static function verify($message, $hash_alg, $r, $s, $p, $q, $g, $y)
 {
     $hash = new CryptHash($hash_alg);
     $hash_m = new MathBigInteger($hash->hash($message), 256);
     $w = $s->modInverse($q);
     $hash_m_mul = $hash_m->multiply($w);
     $u1_base = $hash_m_mul->divide($q);
     $u1 = $u1_base[1];
     $r_mul = $r->multiply($w);
     $u2_base = $r_mul->divide($q);
     $u2 = $u2_base[1];
     $g_pow = $g->modPow($u1, $p);
     $y_pow = $y->modPow($u2, $p);
     $g_pow_mul = $g_pow->multiply($y_pow);
     $g_pow_mul_mod_base = $g_pow_mul->divide($p);
     $g_pow_mul_mod = $g_pow_mul_mod_base[1];
     $v_base = $g_pow_mul_mod->divide($q);
     $v = $v_base[1];
     return $v->compare($r) == 0;
 }