function is_prime($n, $k) { if ($n == 2) { return true; } if ($n < 2 || $n % 2 == 0) { return false; } $d = $n - 1; $s = 0; while ($d % 2 == 0) { $d /= 2; $s++; } for ($i = 0; $i < $k; $i++) { $a = rand(2, $n - 1); $x = bcpowmod($a, $d, $n); if ($x == 1 || $x == $n - 1) { continue; } for ($j = 1; $j < $s; $j++) { $x = bcmod(bcmul($x, $x), $n); if ($x == 1) { return false; } if ($x == $n - 1) { continue 2; } } return false; } return true; }
function powmod($base, $exponent, $modulus) { if (function_exists('gmp_powm')) { // fast return gmp_strval(gmp_powm($base, $exponent, $modulus)); } if (function_exists('bi_powmod')) { // not tested return bi_sto_str(bi_powmod($base, $exponent, $modulus)); } if (function_exists('bcpowmod')) { // slow return bcpowmod($base, $exponent, $modulus); } // emulation, slow $square = bcmod($base, $modulus); $result = 1; while (bccomp($exponent, 0) > 0) { if (bcmod($exponent, 2)) { $result = bcmod(bcmul($result, $square), $modulus); } $square = bcmod(bcmul($square, $square), $modulus); $exponent = bcdiv($exponent, 2); } return $result; }
public static function encryptPortion($portion, $n, $e) { $plain = '0'; foreach (array_reverse($portion) as $k => $v) { $plain = bcadd($plain, bcmul($v, bcpowmod(256, $k, $n))); } $t = self::dec2hex(bcpowmod($plain, $e, $n)); return $t; }
protected function expmod($b, $e, $m) { //if($e==0){return 1;} $t = bcpowmod($b, $e, $m); if ($t[0] === '-') { $t = bcadd($t, $m); } return $t; }
public static function encrypt($text) { $text = self::bchexdec(bin2hex($text)); $n = bcpowmod($text, self::$rsa_exp, self::$rsa_mod); $ret = ''; while ($n > 0) { $ret = chr(bcmod($n, 256)) . $ret; $n = bcdiv($n, 256, 0); } return $ret; }
/** * powmod * Raise a number to a power mod n * This could probably be made faster with some Montgomery trickery, but it's just fallback for now * @param string Decimal string to be raised * @param string Decimal string of the power to raise to * @param string Decimal string the modulus * @return string Decimal string */ function powmod($num, $pow, $mod) { if (function_exists('bcpowmod')) { 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; }
function biDecryptedString($s, $utf8_decoded = FALSE) { $blocks = split(",", $s); $result = ""; for ($i = 0; $i < count($blocks); $i++) { $block = bcpowmod(self::biFromHex($blocks[$i]), $this->d, $this->m); for ($j = 0; $block !== "0"; $j++) { $curchar = bcmod($block, 256); $result .= chr($curchar); $block = bcdiv($block, 256, 0); } } $result = str_replace(chr(255), chr(0), $result); $result = substr($result, 0, strpos($result, chr(254))); return $utf8_decoded ? utf8_decode($result) : $result; }
private function _computeK() { $hash_input = str_pad($this->_Ahex, strlen($this->_srp->Nhex()), "0", STR_PAD_LEFT) . str_pad($this->_Bhex, strlen($this->_srp->Nhex()), "0", STR_PAD_LEFT); $hash_input = pack("H*", $hash_input); $this->_uhex = $this->_srp->hash($hash_input); $this->_udec = hex2dec($this->_uhex); $Stmp = bcpowmod($this->_vdec, $this->_udec, $this->_srp->Ndec()); // v^u (mod N) $Stmp = bcmod(bcmul($Stmp, $this->_Adec), $this->_srp->Ndec()); //v^u*A (mod N) $Stmp = bcpowmod($Stmp, $this->_bdec, $this->_srp->Ndec()); // (v^u*A)^b (mod N) $this->_Sdec = $Stmp; $this->_Shex = dec2hex($this->_Sdec); $this->_Shex = str_pad($this->_Shex, strlen($this->_srp->Nhex()), "0", STR_PAD_LEFT); $this->_Khex = $this->_srp->keyHash(pack("H*", $this->_Shex)); }
public static function modular_exp($base, $exponent, $modulus) { if (extension_loaded('gmp') && USE_EXT == 'GMP') { if ($exponent < 0) { return new ErrorException("Negative exponents (" . $exponent . ") not allowed"); } else { $p = gmp_strval(gmp_powm($base, $exponent, $modulus)); return $p; } } elseif (extension_loaded('bcmath') && USE_EXT == 'BCMATH') { if ($exponent < 0) { return new ErrorException("Negative exponents (" . $exponent . ") not allowed"); } else { $p = bcpowmod($base, $exponent, $modulus); return $p; } } else { throw new ErrorException("Please install BCMATH or GMP"); } }
/** * Create signature for given data * * @param string $data * * @return string */ public function sign($data) { // Make data hash (16 bytes) $base = hash('md4', $data, true); // Add 40 random bytes for ($i = 0; $i < 10; ++$i) { $base .= pack('V', mt_rand()); } // Add length of the base as first 2 bytes $base = pack('v', strlen($base)) . $base; // Modular exponentiation $dec = bcpowmod($this->reverseToDecimal($base), $this->power, $this->modulus); // Convert result to hexadecimal $hex = gmp_strval($dec, 16); // Fill empty bytes with zeros $hex = str_repeat('0', 132 - strlen($hex)) . $hex; // Reverse byte order $hexReversed = ''; for ($i = 0; $i < strlen($hex) / 4; ++$i) { $hexReversed = substr($hex, $i * 4, 4) . $hexReversed; } return strtolower($hexReversed); }
/** * Create a signature for the given data * * @param string $data * * @return string */ public function sign($data) { // Make data hash (16 bytes) $base = hash('md4', $data, true); // Add 40 random bytes for ($i = 0; $i < 10; ++$i) { $base .= pack('V', mt_rand()); } // Add the length of the base (56 = 16 + 40) as the first 2 bytes $base = pack('v', mb_strlen($base, self::MB_ENCODING)) . $base; // Modular exponentiation $dec = bcpowmod(self::reverseToDecimal($base), $this->power, $this->modulus, 0); // Convert to hexadecimal $hex = self::dec2hex($dec); // Fill empty bytes with zeros $hex = str_repeat('0', 132 - mb_strlen($hex, self::MB_ENCODING)) . $hex; // Reverse byte order $hexReversed = ''; for ($i = 0; $i < mb_strlen($hex, self::MB_ENCODING) / 4; ++$i) { $hexReversed = mb_substr($hex, $i * 4, 4, self::MB_ENCODING) . $hexReversed; } return mb_strtolower($hexReversed, self::MB_ENCODING); }
/** * Performs modular exponentiation. * * Here's a quick 'n dirty example: * <code> * <?php * include('Math/BigInteger.php'); * * $a = new Math_BigInteger('10'); * $b = new Math_BigInteger('20'); * $c = new Math_BigInteger('30'); * * $c = $a->modPow($b, $c); * * echo $c->toString(); // outputs 10 * ?> * </code> * * @param Math_BigInteger $e * @param Math_BigInteger $n * @return Math_BigInteger * @access public * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and * and although the approach involving repeated squaring does vastly better, it, too, is impractical * for our purposes. The reason being that division - by far the most complicated and time-consuming * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. * * Modular reductions resolve this issue. Although an individual modular reduction takes more time * then an individual division, when performed in succession (with the same modulo), they're a lot faster. * * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because * the product of two odd numbers is odd), but what about when RSA isn't used? * * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. */ function modPow($e, $n) { $n = $n->abs(); if ($e->compare(new Math_BigInteger()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $temp->modPow($e, $n); } switch (MATH_BIGINTEGER_MODE) { case MATH_BIGINTEGER_MODE_GMP: $temp = new Math_BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); return $temp; case MATH_BIGINTEGER_MODE_BCMATH: // even though the last parameter is optional, according to php.net, it's not optional in // PHP_Compat 1.5.0 when running PHP 4. $temp = new Math_BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $temp; } if (empty($e->value)) { $temp = new Math_BigInteger(); $temp->value = array(1); return $temp; } if ($e->value == array(1)) { list(, $temp) = $this->divide($n); return $temp; } if ($e->value == array(2)) { $temp = $this->_square(); list(, $temp) = $temp->divide($n); return $temp; } // is the modulo odd? if ($n->value[0] & 1) { return $this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY); } // if it's not, it's even // find the lowest set bit (eg. the max pow of 2 that divides $n) for ($i = 0; $i < count($n->value); $i++) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j += 26 * $i; break; } } // at this point, 2^$j * $n/(2^$j) == $n $mod1 = $n->_copy(); $mod1->_rshift($j); $mod2 = new Math_BigInteger(); $mod2->value = array(1); $mod2->_lshift($j); $part1 = $mod1->value != array(1) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $result; }
function powmod($base, $exponent, $modulus) { if (function_exists('bcpowmod')) { return bcpowmod($base, $exponent, $modulus); } else { return $this->_powmod($base, $exponent, $modulus); } }
/** * Gets the remainder of this integer number raised to the integer `$exponent`, divided by the integer `$modulus` * * This method is faster than doing `$num->pow($exponent)->mod($modulus)` * and is primarily useful for cryptographic functionality. * * @throws fValidationException When `$exponent` or `$modulus` is not a valid number * * @param fNumber|string $exponent The power to raise to - all non integer values will be truncated to integers * @param fNumber|string $modulus The value to divide by - all non integer values will be truncated to integers * @return fNumber The remainder */ public function powmod($exponent, $modulus) { $exp = self::parse($exponent, 'array'); $mod = self::parse($modulus, 'array'); if ($this->value[0] == '-') { throw new fProgrammerException('The method %s can only be called for positive number, however this number is negative', 'powmod()'); } if ($exp['integer'][0] == '-') { throw new fProgrammerException('The exponent specified, %s, must be a positive integer, however it is negative', $exponent); } if ($mod['integer'][0] == '-') { throw new fProgrammerException('The modulus specified, %s, must be a positive integer, however it is negative', $modulus); } // All numbers involved in this need to be integers $exponent = $exp['integer']; $modulus = $mod['integer']; $len = strpos($this->value, '.') !== FALSE ? strpos($this->value, '.') : strlen($this->value); $value = substr($this->value, 0, $len); if (function_exists('bcpowmod')) { $result = bcpowmod($value, $exponent, $modulus, 0); } else { $exponent = self::baseConvert($exponent, 10, 2); $result = '+1'; self::performDiv($value, $modulus, $first_modulus); for ($i = 0; $i < strlen($exponent); $i++) { self::performDiv(self::performMul($result, $result), $modulus, $result); if ($exponent[$i] == '1') { self::performDiv(self::performMul($result, $first_modulus), $modulus, $result); } } } return new fNumber($result); }
/** * Raises an arbitrary precision number to another, * reduced by a specified modulus. * * @param string $a The first number. * @param string $b The exponent. * @param string $c The modulus. * @return string The result of the operation. */ public function powmod($a, $b, $c) { return bcpowmod($this->bcNormalize($a), $this->bcNormalize($b), $this->bcNormalize($c)); }
/** * Decrypts a given string with the $dec_key and the $enc_mod * * @param string $encrypted * @param int $dec_key * @param int $enc_mod * @return string */ public function decrypt($encrypted, $dec_key, $enc_mod) { //replaced split with explode $blocks = explode(' ', $encrypted); $result = ""; $max = count($blocks); for ($i = 0; $i < $max; $i++) { $dec = $this->_hex2bint($blocks[$i]); $dec = bcpowmod($dec, $dec_key, $enc_mod); $ascii = $this->_bint2char($dec); $result .= $ascii; } return $this->_redundacyCheck($result); }
/** * powmod using bcmath extension */ function _powmodBcmath($x, $y, $mod) { if (function_exists('bcpowmod')) { return bcpowmod($x, $y, $mod); } else { if (bccomp($y, 1) == 0) { return bcmod($x, $mod); } else { if (bcmod($y, 2) == 0) { return bcmod(bcpow(Security_DSA::_powmodBcmath($x, bcdiv($y, 2), $mod), 2), $mod); } else { return bcmod(bcmul($x, Security_DSA::_powmodBcmath($x, bcsub($y, 1), $mod)), $mod); } } } }
/** * Attempt to create a shared secret with the OpenID Provider. * * @param $op_endpoint URL of the OpenID Provider endpoint. * * @return $assoc_handle The association handle. */ function openid_association($op_endpoint) { //@todo Remove Old Associations: $openid_association = Database::get_main_table(TABLE_MAIN_OPENID_ASSOCIATION); $sql = "DELETE FROM {$openid_association}\n WHERE created + expires_in < '" . api_get_utc_datetime() . "'"; Database::query($sql); // Check to see if we have an association for this IdP already $op_endpoint = Database::escape_string($op_endpoint); $sql = "SELECT assoc_handle\n FROM {$openid_association}\n WHERE idp_endpoint_uri = '{$op_endpoint}'"; $assoc_handle = Database::query($sql); if (Database::num_rows($assoc_handle) <= 1) { $mod = OPENID_DH_DEFAULT_MOD; $gen = OPENID_DH_DEFAULT_GEN; $r = _openid_dh_rand($mod); $private = bcadd($r, 1); $public = bcpowmod($gen, $private, $mod); // If there is no existing association, then request one $assoc_request = openid_association_request($public); $assoc_message = _openid_encode_message(_openid_create_message($assoc_request)); $assoc_headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'); //TODO $assoc_result = openid_http_request($op_endpoint, $assoc_headers, 'POST', $assoc_message); if (isset($assoc_result->error)) { return FALSE; } $assoc_response = _openid_parse_message($assoc_result->data); if (isset($assoc_response['mode']) && $assoc_response['mode'] == 'error') { return FALSE; } if ($assoc_response['session_type'] == 'DH-SHA1') { $spub = _openid_dh_base64_to_long($assoc_response['dh_server_public']); $enc_mac_key = base64_decode($assoc_response['enc_mac_key']); $shared = bcpowmod($spub, $private, $mod); $assoc_response['mac_key'] = base64_encode(_openid_dh_xorsecret($shared, $enc_mac_key)); } //TODO $openid_association = Database::get_main_table(TABLE_MAIN_OPENID_ASSOCIATION); Database::query(sprintf("INSERT INTO {$openid_association} (idp_endpoint_uri, session_type, assoc_handle, assoc_type, expires_in, mac_key, created) VALUES('%s', '%s', '%s', '%s', %d, '%s', %d)", $op_endpoint, $assoc_response['session_type'], $assoc_response['assoc_handle'], $assoc_response['assoc_type'], $assoc_response['expires_in'], $assoc_response['mac_key'], api_get_utc_datetime())); $assoc_handle = $assoc_response['assoc_handle']; } return $assoc_handle; }
/** * Computes the shared secret from the private DH value $dh and the other * party's public value in $pub_key * * @param string $pub_key other party's public value * @param mixed $dh Diffie-Hellman key * @return string * @throws Zend\OpenId\Exception */ public static function computeDhSecret($pub_key, $dh) { if (function_exists('openssl_dh_compute_key')) { $ret = openssl_dh_compute_key($pub_key, $dh); if (ord($ret[0]) > 127) { $ret = "" . $ret; } return $ret; } else { if (extension_loaded('gmp')) { $bn_pub_key = self::binToBigNum($pub_key); $bn_secret = gmp_powm($bn_pub_key, $dh['priv_key'], $dh['p']); return self::bigNumToBin($bn_secret); } else { if (extension_loaded('bcmath')) { $bn_pub_key = self::binToBigNum($pub_key); $bn_secret = bcpowmod($bn_pub_key, $dh['priv_key'], $dh['p']); return self::bigNumToBin($bn_secret); } } } throw new Exception('The system doesn\'t have proper big integer extension', Exception::UNSUPPORTED_LONG_MATH); }
$_SESSION["userId"] = $currentUser->userId; } else { $_SESSION["s"] = "112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00"; $_SESSION["v"] = "112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00"; } $_SESSION["b"] = clipperz_randomSeed(); // $_SESSION["b"] = "5761e6c84d22ea3c5649de01702d60f674ccfe79238540eb34c61cd020230c53"; $_SESSION["B"] = dec2base(bcadd(base2dec($_SESSION["v"], 16), bcpowmod($srp_g, base2dec($_SESSION["b"], 16), $srp_n)), 16); $result["s"] = $_SESSION["s"]; $result["B"] = $_SESSION["B"]; //============================================================= } else { if ($message == "credentialCheck") { $u = clipperz_hash(base2dec($_SESSION["B"], 16)); $A = base2dec($_SESSION["A"], 16); $S = bcpowmod(bcmul($A, bcpowmod(base2dec($_SESSION["v"], 16), base2dec($u, 16), $srp_n)), base2dec($_SESSION["b"], 16), $srp_n); $K = clipperz_hash($S); $M1 = clipperz_hash($A . base2dec($_SESSION["B"], 16) . $K); //$result["B"] = $_SESSION["B"]; //$result["u"] = $u; //$result["A"] = $A; //$result["S"] = $S; //$result["K"] = $K; //$result["M1"] = $M1; //$result["_M1"] = $parameters["parameters"]["M1"]; if ($M1 == $parameters["parameters"]["M1"]) { $_SESSION["K"] = $K; $M2 = clipperz_hash($A . $M1 . $K); $result["M2"] = $M2; $result["connectionId"] = ""; $result["loginInfo"] = array();
/** * Raise an arbitrary precision number to another, reduced by a specified modulus * * @param string $base The left operand, as a string. * @param string $exp The right operand, as a string. * @param string $mod The modulus, as a string. * @access public * @return string|null Returns the result as a string, or <b>NULL</b> if modulus is 0. * @link http://us3.php.net/manual/en/function.bcpowmod.php */ public function powmod($base, $exp, $mod) { return bcpowmod($base, $exp, $mod); }
static function decryptBlock($value, $key) { return bcpowmod($value, $key['private']['d'], $key['private']['n']); }
/** * Shortcut for $this->power($power)->modulus($modulus) * * @param mixed $power the power to raise to * @param mixed $modulus the modulus to apply * * @return Money * * @throws \InvalidArgumentException if the $power is not numeric * @throws \InvalidArgumentException if the $modulus is not numeric */ public function powerModulus($power, $modulus) { if (!is_numeric($power)) { throw new \InvalidArgumentException('Power must be numeric'); } if (!is_numeric($modulus)) { throw new \InvalidArgumentException('Modulus must be numeric'); } // bcscale leads to strange results with modulus operations (which is // why bcmod doesn't even have the parameter...) $amount = bcpowmod($this->amount, strval($power), strval($modulus), 0); return self::valueOf($amount, $this->currency); }
/** * @param ssh\PacketProtocol * @param Side * @param Side * @param mixed array of Key-s if local side is SERVER, string with expected public * key if local side is CLIENT */ function kex(ssh\PacketProtocol $protocol, Side $local, Side $remote, $keys) { $send = $local->type . '_to_' . $remote->type; $receive = $remote->type . '_to_' . $local->type; if ($local->type === Side::CLIENT) { $local_pk_algorithms = array('ssh-dss', 'ssh-rsa'); } else { $local_pk_algorithms = array_keys($keys); } $local->kexinit_packet = ssh\format('brnnnnnnnnnnbu', ssh\SSH_MSG_KEXINIT, ssh\random(16), $local_kex_algorithms = array('diffie-hellman-group1-sha1', 'diffie-hellman-group14-sha1'), $local_pk_algorithms = array('ssh-dss', 'ssh-rsa'), $protocol->getEncryptionAlgorithms(), $protocol->getEncryptionAlgorithms(), $protocol->getMacAlgorithms(), $protocol->getMacAlgorithms(), $protocol->getCompressionAlgorithms(), $protocol->getCompressionAlgorithms(), array(), array(), 0, 0); $protocol->send('r', $local->kexinit_packet); $remote->kexinit_packet = $remote_kexinit = $protocol->receive(); $remote_kexinit = substr($remote_kexinit, 17); list($remote_kex_algorithms, $remote_pk_algorithms, $encryption_algorithms_client_to_server, $encryption_algorithms_server_to_client, $mac_algorithms_client_to_server, $mac_algorithms_server_to_client, $compression_algorithms_client_to_server, $compression_algorithms_server_to_client, $languages_client_to_server, $languages_server_to_client, $first_kex_packet_follows, $reserved) = ssh\parse('nnnnnnnnnnbu', $remote_kexinit); $mistakes = 0; $mistakes += select_algorithm($kex_algorithm, $local_kex_algorithms, $remote_kex_algorithms, $local, $remote, 'kex'); $mistakes += select_algorithm($pk_algorithm, $local_pk_algorithms, $remote_pk_algorithms, $local, $remote, 'public key'); select_algorithm($decryption_algorithm, $protocol->getEncryptionAlgorithms(), ${'encryption_algorithms_' . $remote->type . '_to_' . $local->type}, $local, $remote, 'decryption'); select_algorithm($encryption_algorithm, $protocol->getEncryptionAlgorithms(), ${'encryption_algorithms_' . $local->type . '_to_' . $remote->type}, $local, $remote, 'encryption'); select_algorithm($receive_mac_algorithm, $protocol->getMacAlgorithms(), ${'mac_algorithms_' . $remote->type . '_to_' . $local->type}, $local, $remote, 'receive mac'); select_algorithm($send_mac_algorithm, $protocol->getMacAlgorithms(), ${'mac_algorithms_' . $local->type . '_to_' . $remote->type}, $local, $remote, 'send mac'); select_algorithm($uncompression_algorithm, $protocol->getCompressionAlgorithms(), ${'compression_algorithms_' . $remote->type . '_to_' . $local->type}, $local, $remote, 'uncompression'); select_algorithm($compression_algorithm, $protocol->getCompressionAlgorithms(), ${'compression_algorithms_' . $local->type . '_to_' . $remote->type}, $local, $remote, 'compression'); if ($mistakes > 0 && $first_kex_packet_follows) { for (;;) { $packet = $protocol->receive(); list($packet_type) = ssh\parse('b', $packet); if ($packet_type === ssh\SSH_MSG_DISCONNECT) { list($reason, $description) = ssh\parse('us'); throw new Disconnected($description, $reason); } if ($packet_type === ssh\SSH_MSG_KEXDH_INIT) { break; } } } switch ($kex_algorithm) { // http://tools.ietf.org/html/rfc2409#section-6.2 // http://tools.ietf.org/html/rfc2412#appendix-E.2 case 'diffie-hellman-group1-sha1': $pbin = pack('H*', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'); $random_length = 64; break; // http://tools.ietf.org/html/rfc3526#section-3 // http://tools.ietf.org/html/rfc3526#section-3 case 'diffie-hellman-group14-sha1': $pbin = pack('H*', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'); $random_length = 128; break; } if (!extension_loaded('gmp') && !extension_loaded('bcmath')) { throw new ssh\Error('No extension for mpint calculations.'); } if (extension_loaded('gmp')) { $p = gmp_init(bin2hex($pbin), 16); } else { if (extension_loaded('bcmath')) { $p = bcdebin($pbin); } } if ($local->type === Side::SERVER) { $ybin = ssh\random($random_length); list($packet_type, $ebin) = ssh\parse('bm', $protocol->receive()); if ($packet_type !== ssh\SSH_MSG_KEXDH_INIT) { throw new ssh\Error('Expected SSH_MSG_KEXDH_INIT, got #' . $packet_type . '.'); } if (extension_loaded('gmp')) { $y = gmp_init(bin2hex($ybin), 16); $e = gmp_init(bin2hex($ebin), 16); $f = gmp_powm(2, $y, $p); $K = gmp_powm($e, $y, $p); $fbin = gmp_binval($f); $Kbin = gmp_binval($K); } else { if (extension_loaded('bcmath')) { $y = bcdebin($ybin); $e = bcdebin($ebin); $f = bcpowmod(2, $y, $p); $K = bcpowmod($e, $y, $p); $fbin = bcbin($f); $Kbin = bcbin($K); } } if (!isset($keys[$pk_algorithm])) { throw new ssh\Error('I do not have needed ' . $pk_algorithm . ' key.'); } $key = $keys[$pk_algorithm]; $H = sha1(ssh\format('sssssmmm', $remote->identification_string, $local->identification_string, $remote->kexinit_packet, $local->kexinit_packet, $key->public, $ebin, $fbin, $Kbin), TRUE); if ($protocol->getSessionId() === NULL) { $protocol->setSessionId($H); } $signature = ssh\sign($key->private, $H); $protocol->send('bsms', ssh\SSH_MSG_KEXDH_REPLY, $key->public, $fbin, $signature); } else { asset($local->type === Side::CLIENT); for (;;) { $xbin = ssh\random($random_length); if (extension_loaded('gmp')) { $x = gmp_init(bin2hex($xbin), 16); $cmp = gmp_cmp($x, 0); } else { if (extension_loaded('bcmath')) { $x = bcdebin($xbin); $cmp = bccomp($x, 0); } } if ($cmp > 0) { // if is x > 0 break; } } if (extension_loaded('gmp')) { $e = gmp_powm(2, $x, $p); $ebin = gmp_binval($e); } else { if (extension_loaded('bcmath')) { $e = bcpowmod(2, $x, $p); $ebin = bcbin($e); } } $protocol->send('bm', ssh\SSH_MSG_KEXDH_INIT, $e); list($packet_type) = ssh\parse('b', $packet = $protocol->receive()); if ($packet_type !== ssh\SSH_MSG_KEXDH_REPLY) { throw new ssh\Error('Expected SSH_MSG_KEXDH_REPLY, got #' . $packet_type . '.'); } list($server_key, $fbin, $signature) = ssh\parse('sms', $packet); if ($server_key !== $keys) { throw new ssh\Error('Server keys do not match.'); } if (extension_loaded('gmp')) { $f = gmp_init(bin2hex($fbin), 16); $K = gmp_powm($f, $x, $p); $Kbin = gmp_binval($K); } else { if (extension_loaded('bcmath')) { $f = bcdebin($fbin); $K = bcpowmod($f, $x, $p); $Kbin = bcbin($K); } } $H = sha1(ssh\format('sssssmmm', $local->identification_string, $remote->identification_string, $local->kexinit_packet, $remote->kexinit_packet, $server_key, $ebin, $fbin, $Kbin), TRUE); if (!ssh\verify($server_key, $H, $signature)) { throw new ssh\Error('Server reply cannot be verified.'); } if ($protocol->getSessionId() === NULL) { $protocol->setSessionId($H); } } $iv_client_to_server = sha1(ssh\format('mrbr', $Kbin, $H, ord('A'), $protocol->getSessionId()), TRUE); $iv_server_to_client = sha1(ssh\format('mrbr', $Kbin, $H, ord('B'), $protocol->getSessionId()), TRUE); $key_client_to_server = sha1(ssh\format('mrbr', $Kbin, $H, ord('C'), $protocol->getSessionId()), TRUE); $key_server_to_client = sha1(ssh\format('mrbr', $Kbin, $H, ord('D'), $protocol->getSessionId()), TRUE); $mac_key_client_to_server = sha1(ssh\format('mrbr', $Kbin, $H, ord('E'), $protocol->getSessionId()), TRUE); $mac_key_server_to_client = sha1(ssh\format('mrbr', $Kbin, $H, ord('F'), $protocol->getSessionId()), TRUE); lengthen(${'iv_' . $send}, $protocol->getEncryptionIVLength($encryption_algorithm), $Kbin, $H); lengthen(${'iv_' . $receive}, $protocol->getEncryptionIVLength($decryption_algorithm), $Kbin, $H); lengthen(${'key_' . $send}, $protocol->getEncryptionKeyLength($encryption_algorithm), $Kbin, $H); lengthen(${'key_' . $receive}, $protocol->getEncryptionKeyLength($decryption_algorithm), $Kbin, $H); lengthen(${'mac_key' . $send}, $protocol->getMacKeyLength($send_mac_algorithm), $Kbin, $H); lengthen(${'mac_key' . $receive}, $protocol->getMacKeyLength($receive_mac_algorithm), $Kbin, $H); if ($local->type === Side::SERVER) { list($packet_type) = ssh\parse('b', $protocol->receive()); if ($packet_type !== ssh\SSH_MSG_NEWKEYS) { throw new ssh\Error('Expected SSH_MSG_NEWKEYS, got #' . $packet_type . '.'); } $protocol->initDecryption($decryption_algorithm, ${'key_' . $receive}, ${'iv_' . $receive}); $protocol->initUncompression($uncompression_algorithm); $protocol->initReceiveMac($receive_mac_algorithm, ${'mac_key_' . $receive}); $protocol->send('b', ssh\SSH_MSG_NEWKEYS); $protocol->initEncryption($encryption_algorithm, ${'key_' . $send}, ${'iv_' . $send}); $protocol->initCompression($compression_algorithm); $protocol->initSendMac($send_mac_algorithm, ${'mac_key_' . $send}); } else { asset($local->type === Side::CLIENT); $protocol->send('b', ssh\SSH_MSG_NEWKEYS); $protocol->initEncryption($encryption_algorithm, ${'key_' . $send}, ${'iv_' . $send}); $protocol->initCompression($compression_algorithm); $protocol->initSendMac($send_mac_algorithm, ${'mac_key_' . $send}); list($packet_type) = ssh\parse('b', $protocol->receive()); if ($packet_type !== ssh\SSH_MSG_NEWKEYS) { throw new ssh\Error('Expected SSH_MSG_NEWKEYS, got #' . $packet_type . '.'); } $protocol->initDecryption($decryption_algorithm, ${'key_' . $receive}, ${'iv_' . $receive}); $protocol->initUncompression($uncompression_algorithm); $protocol->initReceiveMac($receive_mac_algorithm, ${'mac_key_' . $receive}); } }
/** * @param string $left_operand * @param string $right_operand * @return string */ public function powmod($left_operand, $right_operand, $modulus) { return bcpowmod($left_operand, $right_operand, $modulus); }
/** * Generates the secret key using the private key and prime * * @param string Public key passed in by the request * * @return string String containing the shared secret */ function fetch_shared_secret($foreignpubkey) { if (function_exists('bcpowmod')) { $this->secret = bcpowmod($foreignpubkey, $this->privatekey, $this->prime); } else { $this->secret = bcmod(bcpow($foreignpubkey, $this->privatekey), $this->prime); } return $this->secret; }
/** * Performs modular exponentiation. * * Here's an example: * <code> * <?php * include 'Math/BigInteger.php'; * * $a = new Math_BigInteger('10'); * $b = new Math_BigInteger('20'); * $c = new Math_BigInteger('30'); * * $c = $a->modPow($b, $c); * * echo $c->toString(); // outputs 10 * ?> * </code> * * @param Math_BigInteger $e * @param Math_BigInteger $n * @return Math_BigInteger * @access public * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and * and although the approach involving repeated squaring does vastly better, it, too, is impractical * for our purposes. The reason being that division - by far the most complicated and time-consuming * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. * * Modular reductions resolve this issue. Although an individual modular reduction takes more time * then an individual division, when performed in succession (with the same modulo), they're a lot faster. * * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because * the product of two odd numbers is odd), but what about when RSA isn't used? * * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. */ function modPow($e, $n) { $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); if ($e->compare(new Math_BigInteger()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $this->_normalize($temp->modPow($e, $n)); } if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP) { $temp = new Math_BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); return $this->_normalize($temp); } if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) { list(, $temp) = $this->divide($n); return $temp->modPow($e, $n); } if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) { $components = array('modulus' => $n->toBytes(true), 'publicExponent' => $e->toBytes(true)); $components = array('modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']), 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])); $RSAPublicKey = pack('Ca*a*a*', 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])), $components['modulus'], $components['publicExponent']); $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA $RSAPublicKey = chr(0) . $RSAPublicKey; $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey; $encapsulated = pack('Ca*a*', 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey); $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($encapsulated)) . '-----END PUBLIC KEY-----'; $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "", STR_PAD_LEFT); if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) { return new Math_BigInteger($result, 256); } } if (MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH) { $temp = new Math_BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $this->_normalize($temp); } if (empty($e->value)) { $temp = new Math_BigInteger(); $temp->value = array(1); return $this->_normalize($temp); } if ($e->value == array(1)) { list(, $temp) = $this->divide($n); return $this->_normalize($temp); } if ($e->value == array(2)) { $temp = new Math_BigInteger(); $temp->value = $this->_square($this->value); list(, $temp) = $temp->divide($n); return $this->_normalize($temp); } return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); // the following code, although not callable, can be run independently of the above code // although the above code performed better in my benchmarks the following could might // perform better under different circumstances. in lieu of deleting it it's just been // made uncallable // is the modulo odd? if ($n->value[0] & 1) { return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); } // if it's not, it's even // find the lowest set bit (eg. the max pow of 2 that divides $n) for ($i = 0; $i < count($n->value); ++$i) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j += 26 * $i; break; } } // at this point, 2^$j * $n/(2^$j) == $n $mod1 = $n->copy(); $mod1->_rshift($j); $mod2 = new Math_BigInteger(); $mod2->value = array(1); $mod2->_lshift($j); $part1 = $mod1->value != array(1) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $this->_normalize($result); }
/** * Performs modular exponentiation. * * Here's an example: * <code> * <?php * include('Math/BigInteger.php'); * * $a = new BigInteger('10'); * $b = new BigInteger('20'); * $c = new BigInteger('30'); * * $c = $a->modPow($b, $c); * * echo $c->toString(); // outputs 10 * ?> * </code> * * @param BigInteger $e * @param BigInteger $n * @return BigInteger * @access public * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and * and although the approach involving repeated squaring does vastly better, it, too, is impractical * for our purposes. The reason being that division - by far the most complicated and time-consuming * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. * * Modular reductions resolve this issue. Although an individual modular reduction takes more time * then an individual division, when performed in succession (with the same modulo), they're a lot faster. * * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because * the product of two odd numbers is odd), but what about when RSA isn't used? * * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. */ function modPow($e, $n) { $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); if ($e->compare(new BigInteger()) < 0) { $e = $e->abs(); $temp = $this->modInverse($n); if ($temp === false) { return false; } return $this->_normalize($temp->modPow($e, $n)); } switch (BigInteger_MODE) { case BigInteger_MODE_GMP: $temp = new BigInteger(); $temp->value = gmp_powm($this->value, $e->value, $n->value); return $this->_normalize($temp); case BigInteger_MODE_BCMATH: $temp = new BigInteger(); $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); return $this->_normalize($temp); } if (empty($e->value)) { $temp = new BigInteger(); $temp->value = array(1); return $this->_normalize($temp); } if ($e->value == array(1)) { list(, $temp) = $this->divide($n); return $this->_normalize($temp); } if ($e->value == array(2)) { $temp = new BigInteger(); $temp->value = $this->_square($this->value); list(, $temp) = $temp->divide($n); return $this->_normalize($temp); } return $this->_normalize($this->_slidingWindow($e, $n, BigInteger_BARRETT)); // is the modulo odd? if ($n->value[0] & 1) { return $this->_normalize($this->_slidingWindow($e, $n, BigInteger_MONTGOMERY)); } // if it's not, it's even // find the lowest set bit (eg. the max pow of 2 that divides $n) for ($i = 0; $i < count($n->value); ++$i) { if ($n->value[$i]) { $temp = decbin($n->value[$i]); $j = strlen($temp) - strrpos($temp, '1') - 1; $j += 26 * $i; break; } } // at this point, 2^$j * $n/(2^$j) == $n $mod1 = $n->copy(); $mod1->_rshift($j); $mod2 = new BigInteger(); $mod2->value = array(1); $mod2->_lshift($j); $part1 = $mod1->value != array(1) ? $this->_slidingWindow($e, $mod1, BigInteger_MONTGOMERY) : new BigInteger(); $part2 = $this->_slidingWindow($e, $mod2, BigInteger_POWEROF2); $y1 = $mod2->modInverse($mod1); $y2 = $mod1->modInverse($mod2); $result = $part1->multiply($mod2); $result = $result->multiply($y1); $temp = $part2->multiply($mod1); $temp = $temp->multiply($y2); $result = $result->add($temp); list(, $result) = $result->divide($n); return $this->_normalize($result); }
/** * Computes $base to the power of $exponent and then applies modulo $modulus. * * @param string $base The number to be exponentiated * @param string $exponent The exponent to apply to $base * @param string $modulus The modulo value to be applied to the result * @return string */ public function powmod($base, $exponent, $modulus) { return bcpowmod($base, $exponent, $modulus); }
public static function powmod($x, $y, $m) { switch (BigInt::support()) { case 'gmp': return gmp_powm($x, $y, $m); case 'big_int': return bi_powmod($x, $y, $m); case 'bcmath': return bcpowmod($x, $y, $m); case '': default: return BigInt::_powmod($x, $y, $m); } }