Example #1
0
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;
}
Example #2
0
 public function xrecover($y)
 {
     $xx = gmp_mul(gmp_sub(gmp_mul($y, $y), 1), $this->inv(gmp_add(gmp_mul(gmp_mul($this->params['d'], $y), $y), 1)));
     $x = gmp_powm($xx, gmp_div_q(gmp_add($this->params['q'], 3), 8), $this->params['q']);
     $t = gmp_mod(gmp_sub(gmp_mul($x, $x), $xx), $this->params['q']);
     if (gmp_cmp($t, 0)) {
         $x = gmp_mod(gmp_mul($x, $this->params['I']), $this->params['q']);
     }
     if (gmp_cmp(gmp_mod($x, 2), 0)) {
         $x = gmp_sub($this->params['q'], $x);
     }
     return $x;
 }
Example #3
0
 /**
  * Construct a new SSH_MSG_KEXDH_REPLY message.
  *
  *  \param fpoirotte::Pssht::Messages::KEXDH::INIT $kexDHInit
  *      Client's contribution to the Diffie-Hellman Key Exchange.
  *
  *  \param fpoirotte::Pssht::PublicKeyInterface $key
  *      Server's public key.
  *
  *  \param fpoirotte::Pssht::EncryptionInterface $encryptionAlgo
  *      Encryption algorithm in use.
  *
  *  \param fpoirotte::Pssht::KEXInterface $kexAlgo
  *      Key exchange algorithm to use.
  *
  *  \param fpoirotte::Pssht::Messages::KEXINIT $serverKEX
  *      Algorithms supported by the server.
  *
  *  \param fpoirotte::Pssht::Messages::KEXINIT $clientKEX
  *      Algorithms supported by the client.
  *
  *  \param string $serverIdent
  *      Server's identification string
  *
  *  \param string $clientIdent
  *      Client's identification string
  */
 public function __construct(\fpoirotte\Pssht\Messages\KEXDH\INIT $kexDHInit, \fpoirotte\Pssht\PublicKeyInterface $key, \fpoirotte\Pssht\EncryptionInterface $encryptionAlgo, \fpoirotte\Pssht\KEXInterface $kexAlgo, \fpoirotte\Pssht\Messages\KEXINIT $serverKEX, \fpoirotte\Pssht\Messages\KEXINIT $clientKEX, $serverIdent, $clientIdent)
 {
     if (!is_string($serverIdent)) {
         throw new \InvalidArgumentException();
     }
     if (!is_string($clientIdent)) {
         throw new \InvalidArgumentException();
     }
     $keyLength = min(20, max($encryptionAlgo->getKeySize(), 16));
     $randBytes = openssl_random_pseudo_bytes(2 * $keyLength);
     $y = gmp_init(bin2hex($randBytes), 16);
     $prime = gmp_init($kexAlgo::getPrime(), 16);
     $this->f = gmp_powm($kexAlgo::getGenerator(), $y, $prime);
     $this->K = gmp_powm($kexDHInit->getE(), $y, $prime);
     $this->K_S = $key;
     $this->kexDHInit = $kexDHInit;
     $this->kexAlgo = $kexAlgo;
     $this->serverKEX = $serverKEX;
     $this->clientKEX = $clientKEX;
     $this->serverIdent = $serverIdent;
     $this->clientIdent = $clientIdent;
     $msgId = chr(\fpoirotte\Pssht\Messages\KEXINIT::getMessageId());
     // $sub is used to create the structure for the hashing function.
     $sub = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer());
     $this->K_S->serialize($sub);
     $K_S = $sub->getBuffer()->get(0);
     $sub->encodeString($this->clientIdent);
     $sub->encodeString($this->serverIdent);
     // $sub2 is used to compute the value
     // of various fields inside the structure.
     $sub2 = new \fpoirotte\Pssht\Wire\Encoder(new \fpoirotte\Pssht\Buffer());
     $sub2->encodeBytes($msgId);
     // Add message identifier.
     $this->clientKEX->serialize($sub2);
     $sub->encodeString($sub2->getBuffer()->get(0));
     $sub2->encodeBytes($msgId);
     // Add message identifier.
     $this->serverKEX->serialize($sub2);
     $sub->encodeString($sub2->getBuffer()->get(0));
     $sub->encodeString($K_S);
     $sub->encodeMpint($this->kexDHInit->getE());
     $sub->encodeMpint($this->f);
     $sub->encodeMpint($this->K);
     $logging = \Plop\Plop::getInstance();
     $origData = $sub->getBuffer()->get(0);
     $data = wordwrap(bin2hex($origData), 4, ' ', true);
     $data = wordwrap($data, 32 + 7, PHP_EOL, true);
     $logging->debug("Signature payload:\r\n%s", array($data));
     $this->H = $this->kexAlgo->hash($origData);
 }
Example #4
0
 public static function calculateV($s, $sha_pass_hash)
 {
     $s = self::hexDecode($s);
     $sha_pass_hash = self::hexDecode($sha_pass_hash);
     if (strlen($s) != 32 || strlen($sha_pass_hash) != 20) {
         throw new exception("calculateV: invalid argument");
     }
     $x = self::hexEncode(strrev(sha1(strrev($s) . $sha_pass_hash, true)));
     $v = gmp_powm(self::$g, gmp_init($x, 16), self::$N);
     $strval = gmp_strval($v, 16);
     // append leading zeros
     while (strlen($strval) < 64) {
         $strval = "0" . $strval;
     }
     return $strval;
 }
Example #5
0
 public function checkAuth($nick, $passwd)
 {
     if (substr($this->pwdHash, 0, 3) === '#1#') {
         // 1st case: new, SHA256 SRP logins
         // https://tools.ietf.org/html/rfc2945#section-3
         $pwdArr = explode('#', $this->pwdHash);
         $x = gmp_import(hash("sha256", base64_decode($pwdArr[2]) . hash("sha256", strtolower($nick) . ':' . $passwd, true), true), 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN);
         $N = gmp_init("AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" . "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" . "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" . "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" . "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" . "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" . "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", 16);
         $g = gmp_init(2);
         $v = gmp_powm($g, $x, $N);
         // strpos to check if the saved has is the same as our hash, minus the possible base64 padding
         return strpos(base64_encode(gmp_export($v, 1, GMP_MSW_FIRST | GMP_BIG_ENDIAN)), $pwdArr[3]) === 0;
     } else {
         // 2nd case: old, pre-SRP logins using salted SHA1
         // src/util/auth.cpp#34 at rev 0bf1984d2c9fb3a9dc73303551c18906c3c9482b
         // https://github.com/minetest/minetest/blob/0bf1984d2c9fb3a9dc73303551c18906c3c9482b/src/util/auth.cpp#L34
         return strpos(base64_encode(hash("sha1", $nick . $passwd, true)), $this->pwdHash) === 0;
     }
     return false;
 }
Example #6
0
 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");
     }
 }
Example #7
0
 /**
  * verify using gmp extendsions
  */
 function _verifyByGmp($message, $sig, $sigKeys)
 {
     $p = $sigKeys['p'];
     $q = $sigKeys['q'];
     $g = $sigKeys['g'];
     $pubKey = $sigKeys['pub_key'];
     list($r_sig, $s_sig) = explode(":", $sig);
     $r_sig = base64_decode($r_sig);
     $s_sig = base64_decode($s_sig);
     $p = gmp_init($p);
     $q = gmp_init($q);
     $g = gmp_init($g);
     $pubKey = gmp_init($pubKey);
     $s1 = Security_DSA::_bindecGmp($r_sig);
     $s2 = Security_DSA::_bindecGmp($s_sig);
     $w = gmp_invert($s2, $q);
     $hash_m = gmp_init('0x' . sha1($message));
     $u1 = gmp_mod(gmp_mul($hash_m, $w), $q);
     $u2 = gmp_mod(gmp_mul($s1, $w), $q);
     $v = gmp_mod(gmp_mod(gmp_mul(gmp_powm($g, $u1, $p), gmp_powm($pubKey, $u2, $p)), $p), $q);
     return gmp_cmp($v, $s1) == 0;
 }
Example #8
0
 /**
  * @param string $left_operand
  * @param string $right_operand
  * @return string
  */
 public function powmod($left_operand, $right_operand, $modulus)
 {
     $result = gmp_powm($left_operand, $right_operand, $modulus);
     return gmp_strval($result);
 }
Example #9
0
/**
 * @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});
    }
}
Example #10
0
 /**
  * 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;
 }
Example #11
0
 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);
     }
 }
Example #12
0
 function generate_login_key($servkey, $username, $password)
 {
     $dhY = "0x9c32cc23d559ca90fc31be72df817d0e124769e809f936bc14360ff4bed758f260a0d596584eacbbc2b88bdd410416163e11dbf62173393fbc0c6fefb2d855f1a03dec8e9f105bbad91b3437d8eb73fe2f44159597aa4053cf788d2f9d7012fb8d7c4ce3876f7d6cd5d0c31754f4cd96166708641958de54a6def5657b9f2e92";
     $dhN = "0xeca2e8c85d863dcdc26a429a71a9815ad052f6139669dd659f98ae159d313d13c6bf2838e10a69b6478b64a24bd054ba8248e8fa778703b418408249440b2c1edd28853e240d8a7e49540b76d120d3b1ad2878b1b99490eb4a2a5e84caa8a91cecbdb1aa7c816e8be343246f80c637abc653b893fd91686cf8d32d6cfe5f2a6f";
     $dhG = "0x5";
     $dhx = "0x" . $this->get_random_hex_key(256);
     if (extension_loaded("gmp")) {
         $dhN = gmp_init($dhN);
         $dhX = gmp_strval(gmp_powm($dhG, $dhx, $dhN), 16);
         $dhK = gmp_strval(gmp_powm($dhY, $dhx, $dhN), 16);
     } else {
         if (extension_loaded("bcmath")) {
             $dhX = $this->bcmath_powm($dhG, $dhx, $dhN);
             $dhK = $this->bcmath_powm($dhY, $dhx, $dhN);
         } else {
             $this->logger->log('error', "generate_login_key(): no idea how to powm...");
             die;
         }
     }
     $str = sprintf("%s|%s|%s", $username, $servkey, $password);
     if (strlen($dhK) < 32) {
         $dhK = str_repeat("0", 32 - strlen($dhK)) . $dhK;
     } else {
         $dhK = substr($dhK, 0, 32);
     }
     $prefix = pack("H16", $this->get_random_hex_key(64));
     $length = 8 + 4 + strlen($str);
     /* prefix, int, ... */
     $pad = str_repeat(" ", (8 - $length % 8) % 8);
     $strlen = pack("N", strlen($str));
     $plain = $prefix . $strlen . $str . $pad;
     $crypted = $this->aochat_crypt($dhK, $plain);
     return $dhX . "-" . $crypted;
 }
Example #13
0
            #echo "New dIC : $deviceID\n";
            $changed = $dbHandle->exec("UPDATE {$dbTable} SET {$dbIDCol} = " . $dbHandle->quote($deviceID) . " WHERE {$dbEmailCol} = " . $email . " AND {$dbKeyCol} = " . $cdkey);
            #echo "Changed rows : $changed\n";
            $cdKeyResponse = $cdKeyPositive;
        } else {
            $cdKeyResponse = $cdKeyNegative;
        }
    }
}
if (!file_exists($client_pub_file)) {
    exit("Decoder : client keys are missing!");
}
$cpb = explode(" ", file_get_contents($client_pub_file));
$cp = gmp_init($cpb[0]);
$cg = gmp_init($cpb[1]);
$cy = gmp_init($cpb[2]);
$cdKeyResponse = mb_convert_encoding($cdKeyResponse, "UTF-8");
$cdKeyCode = "";
for ($i = 0; $i < strlen($cdKeyResponse); $i++) {
    $charCode = unpack("N", mb_convert_encoding($cdKeyResponse[$i], "UCS-4BE", "UTF-8"));
    $cc = decbin(reset($charCode));
    while (strlen($cc) < 8) {
        $cc = "0" . $cc;
    }
    $cdKeyCode = $cdKeyCode . $cc;
}
$cdKeyCode = gmp_init($cdKeyCode, 2);
$cdKeyCodeK = gmp_add(gmp_random(31), "2");
$cdKeyCodeA = gmp_powm($cg, $cdKeyCodeK, $cp);
$cdKeyCodeB = gmp_mod(gmp_mul(gmp_powm($cy, $cdKeyCodeK, $cp), $cdKeyCode), $cp);
echo gmp_strval($cdKeyCodeA) . " " . gmp_strval($cdKeyCodeB);
Example #14
0
 /**
  * @param string $left_operand
  * @param string $right_operand
  * @return string
  */
 public function powmod($left_operand, $right_operand, $modulus)
 {
     return gmp_strval(gmp_powm($left_operand, $right_operand, $modulus));
 }
Example #15
0
function srp_test()
{
    $test_phase = 0;
    //$I = "alice";
    //$P = "password123";
    $I = "aliceasd";
    $P = "passasd98173";
    if ($test_phase == 0) {
        $_GET = array("protocol" => "SRP-6a", "type" => "request", "phase" => 0, "I" => $I, "P" => $P, "hash" => "SHA256", "N_size" => 1024, "enc_client_state" => "");
        $json0 = json_encode(srp());
        echo "Rep0=", $json0, "\n\n";
        $json0 = json_decode($json0, true);
    } else {
        $_GET = array("protocol" => "SRP-6a", "type" => "request", "phase" => 1, "I" => $I, "hash" => "SHA256", "N_size" => 1024, "enc_server_state" => "", "enc_client_state" => "");
        echo "Req1=", json_encode($_GET), "\n\n";
        $json = json_encode(srp());
        echo "Rep1=", $json, "\n\n";
        $json = json_decode($json, true);
        if (strlen($json["N_base36"]) < 100) {
            crit("client: N to small");
        }
        if (strlen($json["s_hex"]) < 32) {
            crit("client: s_hex to small");
        }
        $Ng_ok = false;
        if ($json["g_base36"] == "2" && $json["N_base36"] == "16xa82om033wnlk70asiomztdukuffhyjzvfan3p2mx73a3d7m9hws9a6bzc2ln42n93rmtrxi2p22g3xgxrvyryv9petn2256pdt281msxh9e812rhddxq4oo1f35sp7leese5d02obbwmiui7r2ddwfyqu31ctl4959pckt6lbolnlblhf4znrola2vk3wfto3e8z") {
            $Ng_ok = true;
        }
        if ($Ng_ok != true) {
            crit("client: Ng not whitelisted");
        }
        $N_gmp = gmp_init($json["N_base36"], 36);
        $N_bin = gmp_bytes($N_gmp);
        $g_gmp = gmp_init($json["g_base36"], 36);
        $g_bin = gmp_bytes($g_gmp);
        // check if N,g are secure: large, N is prime and g is primitive root, and discrate logarithm is hard
        // because chacking is hard to do in real-time, they should be whitelisted
        $k_hex = H($N_bin . pad($g_bin));
        $k_gmp = gmp_init($k_hex, 16);
        $s_hex = $json["s_hex"];
        $s_bin = hex2bin($s_hex);
        // client oblicza x = H(s~H(I~P))
        $x_bin = H($s_bin . H($I . ":" . $P));
        $x_hex = bin2hex($x_bin);
        $x_gmp = gmp_init($x_hex, 16);
        // secret
        $v_gmp = gmp_powm($g_gmp, $x_gmp, $N_gmp);
        // secret
        // timing attack
        // client generuje randomowe a
        $a_bin = get_random_bytes(128);
        // rfc 5054: at least 256 bit
        $a_hex = bin2hex($a_bin);
        $a_gmp = gmp_init($a_hex, 16);
        // secret
        // client oblicza A=g^a, i nam wysyla
        $A_gmp = gmp_powm($g_gmp, $a_gmp, $N_gmp);
        // public
        // timing attack
        $A_hex = gmp_strval($A_gmp, 16);
        // debug
        $A_bin = gmp_bytes($A_gmp);
        // ponieważ dostalismy B, możemy obliczyc juz S
        $B_gmp = gmp_init($json["B_base36"], 36);
        $B_hex = gmp_strval($B_gmp, 16);
        // debug
        $B_bin = gmp_bytes($B_gmp);
        // klient oblicza u = H(A~B)
        $u_bin = H(pad($A_bin) . pad($B_bin));
        $u_hex = bin2hex($u_bin);
        $u_gmp = gmp_init($u_hex, 16);
        // klient oblicza S = (B - k*g^x)^(a+u*x)
        //$S_gmp = gmp_powm(gmp_sub($B_gmp, gmp_mul($k_gmp, gmp_powm($g_gmp, $v_gmp, $N_gmp))), gmp_add($a_gmp, gmp_mul($u_gmp, $x_gmp)), $N_gmp);
        $S_gmp = gmp_powm(gmp_mod(gmp_sub($B_gmp, gmp_mod(gmp_mul($k_gmp, $v_gmp), $N_gmp)), $N_gmp), gmp_add($a_gmp, gmp_mul($u_gmp, $x_gmp)), $N_gmp);
        // timing attack
        $S_bin = gmp_bytes($S_gmp);
        $S_hex = gmp_strval($S_gmp, 16);
        // secret
        // klient oblicza M1 = H(A~B~S) i wysyla do serwera
        $M1_bin = H($A_bin . $B_bin . $S_bin);
        $M1_hex = bin2hex($M1_bin);
        $_GET = array("protocol" => "SRP-6a", "type" => "request", "phase" => 2, "A_base36" => gmp_strval($A_gmp, 36), "M1_hex" => $M1_hex, "enc_server_state" => $json["enc_server_state"], "enc_client_state" => "");
        echo "Req2=", json_encode($_GET), "\n\n";
        $json2 = json_encode(srp());
        echo "Rep2=", $json2, "\n\n";
        $json2 = json_decode($json2, true);
        // klient oblicza M2 = H(A~M1~S)
        // klient potwierdza poprawnosc otrzymanego M2
        // klient oblicza K = H(S)
        // klient oblicza M = H( (H(N) xor H(g))~H(I)~s~A~B~K )
        $M2_bin = H($A_bin . $M1_bin . $S_bin);
        $M2_hex = bin2hex($M2_bin);
        if ($M2_hex != $json2["M2_hex"]) {
            crit("client: M2 are different, don't trust server!");
        }
        $K_bin = H($S_bin);
        $K_hex = bin2hex($K_bin);
        // secret
        $M_bin = HM((H($N_bin) ^ H($g_bin)) . H($I) . $s_bin . $A_bin . $B_bin, $K_bin);
        $M_hex = bin2hex($M_bin);
        $_GET = array("protocol" => "SRP-6a", "type" => "request", "phase" => 3, "M_hex" => $M_hex, "enc_server_state" => $json2["enc_server_state"], "enc_client_state" => "");
        echo "Req3=", json_encode($_GET), "\n\n";
        $json3 = json_encode(srp());
        echo "Rep3=", $json3, "\n\n";
        $json3 = json_decode($json3, true);
        $Z_bin = HM($A_bin . $M_bin, $K_bin);
        $Z_hex = bin2hex($Z_bin);
        if ($Z_hex != $json3["Z_hex"]) {
            crit("Z_hex different");
        }
        echo "Logged\n";
    }
}
Example #16
0
 private function DoPublic($x)
 {
     if ($this->canEncrypt) {
         return gmp_powm($x, $this->e, $this->n);
     }
     return 0;
 }
 public static function gmp_squareRootModP($prime, $verbose = false)
 {
     $start_time = microtime(true);
     if ($verbose) {
         echo "Testing primes for modulus " . $prime . "<br />";
     }
     $squares = array();
     for ($root = 0; gmp_cmp($root, gmp_add(1, gmp_div($prime, 2))) < 0; $root = gmp_add($root, 1)) {
         $sq = gmp_strval(gmp_powm($root, 2, $prime));
         $calculated = NumberTheory::square_root_mod_prime($sq, $prime);
         $calc_sq = gmp_strval(gmp_powm($calculated, 2, $prime));
         if (gmp_cmp($calculated, $root) != 0 && gmp_cmp(gmp_sub($prime, $calculated), $root) != 0) {
             $error_tally++;
             echo "FAILED TO FIND " . gmp_strval($root) . " AS sqrt(" . gmp_strval($sq) . ") mod {$prime} . Said {$calculated} (" . ($prime - $calculated) . ") <br />\n";
             flush();
         } else {
             if ($verbose) {
                 echo "SUCCESS TO FIND " . gmp_strval($root) . " AS sqrt(" . gmp_strval($sq) . ") mod {$prime} . Said {$calculated} (" . ($prime - $calculated) . ") <br />\n";
             }
             flush();
         }
     }
     $end_time = microtime(true);
     $time_res = $end_time - $start_time;
     echo "<br />Square roots mod " . $prime . " took: " . $time_res . " seconds. <br />";
 }
Example #18
0
 function bigint_powmod($x, $y, $m)
 {
     return gmp_powm($x, $y, $m);
 }
Example #19
0
 /**
  * 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);
 }
Example #20
0
 function powm($base, $exponent, $modulus)
 {
     if (function_exists('gmp_powm')) {
         return gmp_strval(gmp_powm($base, $exponent, $modulus));
     } else {
         if (function_exists('bi_powmod')) {
             return bi_sto_str(bi_powmod($base, $exponent, $modulus));
         } else {
             if (function_exists('bcpowmod')) {
                 return bcpowmod($base, $exponent, $modulus);
             } else {
                 if (preg_match("/^\\d+,\\d+,\\d+\$/", "{$base},{$exponent},{$modulus}")) {
                     //@FIX: this is insecure - a bi-directional proc_open() is required
                     if (is_executable("/usr/bin/python")) {
                         $r = trim(`python -c "print pow({$base}, {$exponent}, {$modulus})"`);
                     } else {
                         $r = trim(`perl -e "use Math::BigInt; print Math::BigInt->new('{$base}')->bmodpow('{$exponent}', '{$modulus}')->bstr();"`);
                     }
                     if (preg_match("/^\\d+\$/", $r)) {
                         return $r;
                     }
                 }
             }
         }
     }
     trigger_error("powmod: unsupported or non-integer argument", E_USER_ERROR);
 }
Example #21
0
 /**
  * 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)
 {
     $this->secret = gmp_powm($foreignpubkey, $this->privatekey, $this->prime);
     return gmp_strval($this->secret);
 }
Example #22
0
 /**
  * Raise to a power and reduce by a modulus
  *
  * @param mixed $power
  * @param mixed $modulus
  * @access public
  * @return self
  */
 public function powMod($power, $modulus)
 {
     $result = gmp_powm($this->getRawValue(), static::upgradeParam($power)->getRawValue(), static::upgradeParam($modulus)->getRawValue());
     return static::factory($result);
 }
Example #23
0
 function powmod($base, $exponent, $modulus)
 {
     return gmp_powm($base, $exponent, $modulus);
 }
Example #24
0
File: Gmp.php Project: zae/bigmath
 public function PowMod($left, $right, $modulus)
 {
     return $this->string(gmp_powm($left, $right, $modulus));
 }
Example #25
0
 /**
  * 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);
 }
Example #26
0
 public function validatePoint($x, $y)
 {
     $a = $this->a;
     $b = $this->b;
     $p = $this->p;
     $x = gmp_init($x, 16);
     $y2 = gmp_mod(gmp_add(gmp_add(gmp_powm($x, gmp_init(3, 10), $p), gmp_mul($a, $x)), $b), $p);
     $y = gmp_mod(gmp_pow(gmp_init($y, 16), 2), $p);
     if (gmp_cmp($y2, $y) == 0) {
         return true;
     } else {
         return false;
     }
 }
Example #27
0
 /**
  * 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);
 }
Example #28
0
 function bcpowmod($x, $y, $mod)
 {
     return gmp_strval(gmp_powm($x, $y, $mod));
 }
Example #29
0
 /**
  * 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);
 }
Example #30
0
$pop1 = gmp_init("10000101", 2);
// 3 1's
echo gmp_popcount($pop1) . "\n";
$pop2 = gmp_init("11111110", 2);
// 7 1's
echo gmp_popcount($pop2) . "\n";
// gmp_pow
$pow1 = gmp_pow("2", 31);
echo gmp_strval($pow1) . "\n";
$pow2 = gmp_pow("0", 0);
echo gmp_strval($pow2) . "\n";
$pow3 = gmp_pow("2", -1);
// Negative exp, generates warning
echo gmp_strval($pow3) . "\n";
// gmp_powm
$pow1 = gmp_powm("2", "31", "2147483649");
echo gmp_strval($pow1) . "\n";
// gmp_prob_prime
echo gmp_prob_prime("6") . "\n";
// definitely not a prime
echo gmp_prob_prime("1111111111111111111") . "\n";
// probably a prime
echo gmp_prob_prime("11") . "\n";
// definitely a prime
// gmp_random -- not implemented
// gmp_scan0
// "0" bit is found at position 3. index starts at 0
$s1 = gmp_init("10111", 2);
echo gmp_scan0($s1, 0) . "\n";
// "0" bit is found at position 7. index starts at 5
$s2 = gmp_init("101110000", 2);