diff --git a/composer.json b/composer.json index b720ab54..9f880285 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "phpseclib/phpseclib": "^2.0", "paragonie/constant_time_encoding": "^1|^2", "paragonie/random_compat": "^2.0", - "php": ">=5.6.0" + "php": ">=5.6.0", + "icicleio/icicle": "^0.9.6" }, "authors": [ { diff --git a/composer.lock b/composer.lock index 79f7f6ad..96dbe52e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "8d6fcaae1bc321e5d42b8b4749ea4266", - "content-hash": "d004c37ebd93efd29d86d09824fdd71b", + "hash": "966d0bc73f86b42249ee2a37fea56e64", + "content-hash": "c5463d805ceb0061da4eca7c688a973e", "packages": [ { "name": "danog/phpstruct", @@ -55,6 +55,72 @@ ], "time": "2016-08-14 17:51:55" }, + { + "name": "icicleio/icicle", + "version": "v0.9.6", + "source": { + "type": "git", + "url": "https://github.com/icicleio/icicle.git", + "reference": "84a3cc6f7dc38500f4ed9bdae79f458d191cb119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/icicleio/icicle/zipball/84a3cc6f7dc38500f4ed9bdae79f458d191cb119", + "reference": "84a3cc6f7dc38500f4ed9bdae79f458d191cb119", + "shasum": "" + }, + "require": { + "php": "^5.5|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "suggest": { + "ext-ev": "Provides an event loop with better performance.", + "ext-pcntl": "Enables custom signal handling." + }, + "type": "library", + "autoload": { + "psr-4": { + "Icicle\\": "src" + }, + "files": [ + "src/functions.php", + "src/Awaitable/functions.php", + "src/Coroutine/functions.php", + "src/Loop/functions.php", + "src/Observable/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@icicle.io" + } + ], + "description": "Icicle is a PHP library for writing asynchronous code using synchronous coding techniques.", + "homepage": "http://icicle.io", + "keywords": [ + "Socket", + "async", + "asynchronous", + "awaitable", + "coroutine", + "event", + "generator", + "interruptible", + "multitasking", + "network", + "promise", + "server", + "stream" + ], + "time": "2016-03-31 16:34:26" + }, { "name": "paragonie/constant_time_encoding", "version": "v2.0.3", diff --git a/src/danog/MadelineProto/Session.php b/src/danog/MadelineProto/Session.php index c3d2107c..d9877fe5 100644 --- a/src/danog/MadelineProto/Session.php +++ b/src/danog/MadelineProto/Session.php @@ -92,7 +92,10 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $this->seq_no = 0; $this->timedelta = 0; // time delta - $this->message_ids = []; + $this->incoming_message_ids = []; + $this->outgoing_message_ids = []; + $this->ack_incoming_message_ids = []; + $this->ack_outgoing_message_ids = []; if ($this->settings['authorization']['temp_auth_key'] == null || $this->settings['authorization']['auth_key'] == null) { if ($this->settings['authorization']['auth_key'] == null) { @@ -107,7 +110,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB unset($this->sock); } - public function check_message_id($new_message_id, $from_client) + public function check_message_id($new_message_id, $outgoing) { $new_message_id = $this->struct->unpack('timedelta - 300) * pow(2, 30)) * 4) > $new_message_id) { @@ -116,23 +119,57 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB if (((int) ((time() + $this->timedelta + 30) * pow(2, 30)) * 4) < $new_message_id) { throw new Exception('Given message id is too new.'); } - if ($from_client) { + if ($outgoing) { if ($new_message_id % 4 != 0) { throw new Exception('Given message id is not divisible by 4.'); } - } else { - if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) { - throw new Exception('message id mod 4 != 1 or 3'); - } - foreach ($this->message_ids as $message_id) { + foreach ($this->outgoing_message_ids as $message_id) { if ($new_message_id <= $message_id) { throw new Exception('Given message id is lower than or equal than the current limit ('.$message_id.').'); } } - $this->message_ids[] = $new_message_id; - if (count($this->message_ids) > $this->settings['authorization']['message_ids_limit']) { - array_shift($this->message_ids); + $this->outgoing_message_ids[] = $new_message_id; + if (count($this->outgoing_message_ids) > $this->settings['authorization']['message_ids_limit']) { + array_shift($this->outgoing_message_ids); } + + } else { + if ($new_message_id % 4 != 1 && $new_message_id % 4 != 3) { + throw new Exception('message id mod 4 != 1 or 3'); + } + foreach ($this->incoming_message_ids as $message_id) { + if ($new_message_id <= $message_id) { + throw new Exception('Given message id is lower than or equal than the current limit ('.$message_id.').'); + } + } + $this->incoming_message_ids[] = $new_message_id; + if (count($this->incoming_message_ids) > $this->settings['authorization']['message_ids_limit']) { + array_shift($this->incoming_message_ids); + } + } + } + + public function ack_outgoing_message_id($message_id) { + $message_id = $this->struct->unpack('outgoing_message_ids)) { + throw new Exception("Couldn't find message id ".$message_id." in the array of outgoing message ids. Maybe try to increase its size?"); + } + $this->ack_outgoing_message_ids[] = $message_id; + if (count($this->ack_outgoing_message_ids) > $this->settings['authorization']['message_ids_limit']) { + array_shift($this->ack_outgoing_message_ids); + } + } + public function ack_incoming_message_id($message_id) { + $message_id = $this->struct->unpack('incoming_message_ids)) { + throw new Exception("Couldn't find message id ".$message_id." in the array of incoming message ids. Maybe try to increase its size?"); + } + $this->object_call('msgs_ack', ['msg_ids' => [$message_id]]); + $this->ack_incoming_message_ids[] = $message_id; + if (count($this->ack_incoming_message_ids) > $this->settings['authorization']['message_ids_limit']) { + array_shift($this->ack_incoming_message_ids); } } @@ -146,10 +183,6 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB return ($value * 2) + $in; } - public function acknowledge($msg_id) - { - return $this->object_call('msgs_ack', ['msg_ids' => [$msg_id]]); - } /** * Forming the message frame and sending message to server @@ -161,6 +194,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $this->check_message_id($message_id, true); if (($this->settings['authorization']['temp_auth_key']['auth_key'] == null) || ($this->settings['authorization']['temp_auth_key']['server_salt'] == null)) { $message = Tools::string2bin('\x00\x00\x00\x00\x00\x00\x00\x00').$message_id.$this->struct->pack('last_sent = ["message_id" => $message_id]; } else { $seq_no = $this->generate_seq_no($content_related); $encrypted_data = $this->settings['authorization']['temp_auth_key']['server_salt'].$this->settings['authorization']['session_id'].$message_id.$this->struct->pack('aes_calculate($message_key); $message = $this->settings['authorization']['temp_auth_key']['id'].$message_key.Crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); + $this->last_sent = ["message_id" => $message_id, "seq_no" => $seq_no]; } $this->sock->send_message($message); } @@ -186,6 +221,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB list($message_id, $message_length) = $this->struct->unpack('<8sI', fread($payload, 12)); $this->check_message_id($message_id, false); $message_data = fread($payload, $message_length); + $this->last_received = ["message_id" => $message_id]; } elseif ($auth_key_id == $this->settings['authorization']['temp_auth_key']['id']) { $message_key = fread($payload, 16); $encrypted_data = stream_get_contents($payload); @@ -230,19 +266,18 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB if ($message_key != substr(sha1(substr($decrypted_data, 0, 32 + $message_data_length), true), -16)) { throw new Exception('msg_key mismatch'); } - //$this->acknowledge($message_id); + $this->last_received = ["message_id" => $message_id, "seq_no" => $seq_no]; } else { throw new Exception('Got unknown auth_key id'); } - return $message_data; } - public function method_call($method, $kwargs) + public function method_call($method, $args) { foreach (range(1, $this->settings['max_tries']['query']) as $i) { try { - $this->send_message($this->tl->serialize_method($method, $kwargs), $this->tl->content_related($method)); + $this->send_message($this->tl->serialize_method($method, $args), $this->tl->content_related($method)); $server_answer = $this->recv_message(); } catch (Exception $e) { $this->log->log('An error occurred while calling method '.$method.': '.$e->getMessage().' in '.$e->getFile().':'.$e->getLine().'. Recreating connection and retrying to call method...'); @@ -254,10 +289,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB throw new Exception('An error occurred while calling method '.$method.'.'); } $deserialized = $this->tl->deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $server_answer)); - switch ($deserialized["_"]) { - - } - return $deserialized; + return $this->handle_response($deserialized, $method, $args); } throw new Exception('An error occurred while calling method '.$method.'.'); } @@ -282,12 +314,52 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB } throw new Exception('An error occurred while calling object '.$object.'.'); } + public function handle_response($response, $name, $args) { + switch ($response["_"]) { + case "rpc_result": + $this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response + $this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received my + + return $this->handle_response($response, $name, $args); + break; + case "rpc_error": + throw new Exception("Got rpc error " . $response["error_code"] . ": " . $response["error_message"]); + break; + case "rpc_answer_unknown": + $this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message + return $response; // I'm not handling this error + break; + case "rpc_answer_dropped_running": + $this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response + $this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message + + $this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received the original query (the same one, the response to which we wish to forget) + return $response; // I'm not handling this + break; + case "rpc_answer_dropped": + $this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response + $this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message + + $this->ack_outgoing_message_id($response["req_msg_id"]); // Acknowledge that the server received the original query (the same one, the response to which we wish to forget) + return $response; // I'm not handling this + break; + case "future_salts": + $this->ack_outgoing_message_id($this->last_sent["message_id"]); // Acknowledge that the server received my message + + break; + default: + $this->ack_incoming_message_id($this->last_received["message_id"]); // Acknowledge that I received the server's response + return $response; + break; + } + + } public function create_auth_key($expires_in = -1) { foreach (Tools::range(0, $this->settings['max_tries']['authorization']) as $retry_id_total) { // Make pq request - $nonce = \phpseclib\Crypt\Random::string(16); + $nonce = \phpseclib\Crypt\Random::string(16); $this->log->log('Handshake: Requesting pq'); $ResPQ = $this->method_call('req_pq', ['nonce' => $nonce]); $server_nonce = $ResPQ['server_nonce']; @@ -305,8 +377,8 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB throw new Exception("Handshake: couldn't find our key in the server_public_key_fingerprints vector."); } $pq_bytes = $ResPQ['pq']; - // Compute p and q - $pq = new \phpseclib\Math\BigInteger($pq_bytes, 256); + // Compute p and q + $pq = new \phpseclib\Math\BigInteger($pq_bytes, 256); list($p, $q) = $this->PrimeModule->primefactors($pq); $p = new \phpseclib\Math\BigInteger($p); $q = new \phpseclib\Math\BigInteger($q); @@ -320,8 +392,8 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $this->log->log(sprintf('Factorization %s = %s * %s', $pq, $p, $q)); - // Serialize object for req_DH_params - $p_bytes = $this->struct->pack('>I', (string) $p); + // Serialize object for req_DH_params + $p_bytes = $this->struct->pack('>I', (string) $p); $q_bytes = $this->struct->pack('>I', (string) $q); $new_nonce = \phpseclib\Crypt\Random::string(32); @@ -332,27 +404,27 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB } $sha_digest = sha1($data, true); - // Encrypt serialized object - $random_bytes = \phpseclib\Crypt\Random::string(255 - strlen($data) - strlen($sha_digest)); + // Encrypt serialized object + $random_bytes = \phpseclib\Crypt\Random::string(255 - strlen($data) - strlen($sha_digest)); $to_encrypt = $sha_digest.$data.$random_bytes; $encrypted_data = $this->key->encrypt($to_encrypt); - // req_DH_params - $this->log->log('Starting Diffie Hellman key exchange'); + // req_DH_params + $this->log->log('Starting Diffie Hellman key exchange'); $server_dh_params = $this->method_call('req_DH_params', - [ - 'nonce' => $nonce, - 'server_nonce' => $server_nonce, - 'p' => $p_bytes, - 'q' => $q_bytes, - 'public_key_fingerprint' => $public_key_fingerprint, - 'encrypted_data' => $encrypted_data, - ] - ); - // Check nonce and server_nonce - if ($nonce != $server_dh_params['nonce']) { - throw new Exception('Handshake: wrong nonce.'); - } + [ + 'nonce' => $nonce, + 'server_nonce' => $server_nonce, + 'p' => $p_bytes, + 'q' => $q_bytes, + 'public_key_fingerprint' => $public_key_fingerprint, + 'encrypted_data' => $encrypted_data, + ] + ); + // Check nonce and server_nonce + if ($nonce != $server_dh_params['nonce']) { + throw new Exception('Handshake: wrong nonce.'); + } if ($server_nonce != $server_dh_params['server_nonce']) { throw new Exception('Handshake: wrong server nonce.'); } @@ -360,21 +432,21 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB throw new Exception('Handshake: wrong new nonce hash.'); } - // Get key and iv and decrypt answer - $encrypted_answer = $server_dh_params['encrypted_answer']; + // Get key and iv and decrypt answer + $encrypted_answer = $server_dh_params['encrypted_answer']; $tmp_aes_key = sha1($new_nonce.$server_nonce, true).substr(sha1($server_nonce.$new_nonce, true), 0, 12); $tmp_aes_iv = substr(sha1($server_nonce.$new_nonce, true), 12, 8).sha1($new_nonce.$new_nonce, true).substr($new_nonce, 0, 4); $answer_with_hash = Crypt::ige_decrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv); - // Separate answer and hash - $answer_hash = substr($answer_with_hash, 0, 20); + // Separate answer and hash + $answer_hash = substr($answer_with_hash, 0, 20); $answer = substr($answer_with_hash, 20); - // Deserialize - $server_DH_inner_data = $this->tl->deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); + // Deserialize + $server_DH_inner_data = $this->tl->deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); - // Do some checks - $server_DH_inner_data_length = $this->tl->get_length(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); + // Do some checks + $server_DH_inner_data_length = $this->tl->get_length(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); if (sha1(substr($answer, 0, $server_DH_inner_data_length), true) != $answer_hash) { throw new Exception('Handshake: answer_hash mismatch.'); } @@ -388,78 +460,78 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $g_a = new \phpseclib\Math\BigInteger($server_DH_inner_data['g_a'], 256); $dh_prime = new \phpseclib\Math\BigInteger($server_DH_inner_data['dh_prime'], 256); - // Time delta - $server_time = $server_DH_inner_data['server_time']; + // Time delta + $server_time = $server_DH_inner_data['server_time']; $this->timedelta = ($server_time - time()); $this->log->log(sprintf('Server-client time delta = %.1f s', $this->timedelta)); - // Define some needed numbers for BigInteger - $one = new \phpseclib\Math\BigInteger(1); + // Define some needed numbers for BigInteger + $one = new \phpseclib\Math\BigInteger(1); $two = new \phpseclib\Math\BigInteger(2); $twoe2047 = new \phpseclib\Math\BigInteger('16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328'); $twoe2048 = new \phpseclib\Math\BigInteger('32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656'); - // Check validity of dh_prime - if (!$dh_prime->isPrime()) { - throw new Exception("Handshake: dh_prime isn't a safe 2048-bit prime (dh_prime isn't a prime)."); - } - /* - // Almost always fails - if (!$dh_prime->subtract($one)->divide($two)[0]->isPrime()) { - throw new Exception("Handshake: dh_prime isn't a safe 2048-bit prime ((dh_prime - 1) / 2 isn't a prime)."); - } - */ - // 2^2047 < dh_prime < 2^2048 - if ($dh_prime->compare($twoe2047) <= 0 // 2^2047 < dh_prime or dh_prime > 2^2047 or ! dh_prime <= 2^2047 - || $dh_prime->compare($twoe2048) >= 0 // dh_prime < 2^2048 or ! dh_prime >= 2^2048 - ) { - throw new Exception("Handshake: g isn't a safe 2048-bit prime (2^2047 < dh_prime < 2^2048 is false)."); - } + // Check validity of dh_prime + if (!$dh_prime->isPrime()) { + throw new Exception("Handshake: dh_prime isn't a safe 2048-bit prime (dh_prime isn't a prime)."); + } + /* + // Almost always fails + if (!$dh_prime->subtract($one)->divide($two)[0]->isPrime()) { + throw new Exception("Handshake: dh_prime isn't a safe 2048-bit prime ((dh_prime - 1) / 2 isn't a prime)."); + } + */ + // 2^2047 < dh_prime < 2^2048 + if ($dh_prime->compare($twoe2047) <= 0 // 2^2047 < dh_prime or dh_prime > 2^2047 or ! dh_prime <= 2^2047 + || $dh_prime->compare($twoe2048) >= 0 // dh_prime < 2^2048 or ! dh_prime >= 2^2048 + ) { + throw new Exception("Handshake: g isn't a safe 2048-bit prime (2^2047 < dh_prime < 2^2048 is false)."); + } - // Check validity of g - // 1 < g < dh_prime - 1 - if ($g->compare($one) <= 0 // 1 < g or g > 1 or ! g <= 1 - || $g->compare($dh_prime->subtract($one)) >= 0 // g < dh_prime - 1 or ! g >= dh_prime - 1 - ) { - throw new Exception('Handshake: g is invalid (1 < g < dh_prime - 1 is false).'); - } + // Check validity of g + // 1 < g < dh_prime - 1 + if ($g->compare($one) <= 0 // 1 < g or g > 1 or ! g <= 1 + || $g->compare($dh_prime->subtract($one)) >= 0 // g < dh_prime - 1 or ! g >= dh_prime - 1 + ) { + throw new Exception('Handshake: g is invalid (1 < g < dh_prime - 1 is false).'); + } - // Check validity of g_a - // 1 < g_a < dh_prime - 1 - if ($g_a->compare($one) <= 0 // 1 < g_a or g_a > 1 or ! g_a <= 1 - || $g_a->compare($dh_prime->subtract($one)) >= 0 // g_a < dh_prime - 1 or ! g_a >= dh_prime - 1 - ) { - throw new Exception('Handshake: g_a is invalid (1 < g_a < dh_prime - 1 is false).'); - } + // Check validity of g_a + // 1 < g_a < dh_prime - 1 + if ($g_a->compare($one) <= 0 // 1 < g_a or g_a > 1 or ! g_a <= 1 + || $g_a->compare($dh_prime->subtract($one)) >= 0 // g_a < dh_prime - 1 or ! g_a >= dh_prime - 1 + ) { + throw new Exception('Handshake: g_a is invalid (1 < g_a < dh_prime - 1 is false).'); + } foreach (Tools::range(0, $this->settings['max_tries']['authorization']) as $retry_id) { $b = new \phpseclib\Math\BigInteger(\phpseclib\Crypt\Random::string(256), 256); $g_b = $g->powMod($b, $dh_prime); - // Check validity of g_b - // 1 < g_b < dh_prime - 1 - if ($g_b->compare($one) <= 0 // 1 < g_b or g_b > 1 or ! g_b <= 1 - || $g_b->compare($dh_prime->subtract($one)) >= 0 // g_b < dh_prime - 1 or ! g_b >= dh_prime - 1 - ) { - throw new Exception('Handshake: g_b is invalid (1 < g_b < dh_prime - 1 is false).'); - } + // Check validity of g_b + // 1 < g_b < dh_prime - 1 + if ($g_b->compare($one) <= 0 // 1 < g_b or g_b > 1 or ! g_b <= 1 + || $g_b->compare($dh_prime->subtract($one)) >= 0 // g_b < dh_prime - 1 or ! g_b >= dh_prime - 1 + ) { + throw new Exception('Handshake: g_b is invalid (1 < g_b < dh_prime - 1 is false).'); + } $g_b_str = $g_b->toBytes(); - // serialize client_DH_inner_data - $data = $this->tl->serialize_obj('client_DH_inner_data', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'retry_id' => $retry_id, 'g_b' => $g_b_str]); + // serialize client_DH_inner_data + $data = $this->tl->serialize_obj('client_DH_inner_data', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'retry_id' => $retry_id, 'g_b' => $g_b_str]); $data_with_sha = sha1($data, true).$data; $data_with_sha_padded = $data_with_sha.\phpseclib\Crypt\Random::string(Tools::posmod(-strlen($data_with_sha), 16)); - // encrypt client_DH_inner_data - $encrypted_data = Crypt::ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); + // encrypt client_DH_inner_data + $encrypted_data = Crypt::ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); - // Send set_client_DH_params query - $Set_client_DH_params_answer = $this->method_call('set_client_DH_params', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'encrypted_data' => $encrypted_data]); + // Send set_client_DH_params query + $Set_client_DH_params_answer = $this->method_call('set_client_DH_params', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'encrypted_data' => $encrypted_data]); - // Generate auth_key - $auth_key = $g_a->powMod($b, $dh_prime); + // Generate auth_key + $auth_key = $g_a->powMod($b, $dh_prime); $auth_key_str = $auth_key->toBytes(); $auth_key_sha = sha1($auth_key_str, true); $auth_key_aux_hash = substr($auth_key_sha, 0, 8);