From a698e91dd304e43ce70923e17dd5c0b5622b8200 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 9 Jun 2017 20:56:13 +0100 Subject: [PATCH] Fixed CTR encryption and downloading of CDN files --- bot.php | 3 +- src/danog/MadelineProto/MTProto.php | 28 +++++++++++--- .../MTProtoTools/AuthKeyHandler.php | 11 ------ .../MadelineProto/MTProtoTools/Crypt.php | 3 +- .../MadelineProto/MTProtoTools/Files.php | 37 ++++++++++--------- .../MTProtoTools/MsgIdHandler.php | 6 +-- tests/testing.php | 2 +- 7 files changed, 49 insertions(+), 41 deletions(-) diff --git a/bot.php b/bot.php index 8f15386a..46d0320e 100755 --- a/bot.php +++ b/bot.php @@ -27,7 +27,8 @@ try { die; } } -var_dump($MadelineProto->rle_decode($MadelineProto->base64url_decode('gRuWfE2EXVJtaecDLpxYs39tElkZtzLo2mwsdmkuRbZQLO6ofKSoTHedbY1N9lAeUfvgE8wqHIF1VJ95YIyCCLswdZlmf-RWdph_C8wcUeSxtNCTE1gdbmiZp77uIT77bDbUHHbNyfgsKwY30aZS91snXwIrOulsGGA_j7VQ0k9TzGO9AczSj0LZt6kVpPpXKqSraHopH59Tpv4UCX3qXPa5XbcyodpOIL_VN5TtpfEUxoF5asavCOgNj6V4KInLDjkpLr-8dgViLUGRZagxr0EFHUs7DT9dW66_A4_qnszPlIw6GHOIlhLxV8emke0JV_hvATN11uT_RlnHNY83vQ'))); +//var_dump($MadelineProto->API->get_config([], ['datacenter' => $MadelineProto->API->datacenter->curdc])); +//var_dump($MadelineProto->API->settings['connection']); $offset = 0; while (true) { diff --git a/src/danog/MadelineProto/MTProto.php b/src/danog/MadelineProto/MTProto.php index 4f2d974c..0424b322 100644 --- a/src/danog/MadelineProto/MTProto.php +++ b/src/danog/MadelineProto/MTProto.php @@ -603,20 +603,24 @@ class MTProto extends \Volatile if (strpos($id, 'media')) { continue; } + $cdn = strpos($id, 'cdn'); if ($socket->session_id === null) { $socket->session_id = $this->random(8); $socket->session_in_seq_no = 0; $socket->session_out_seq_no = 0; } if ($socket->temp_auth_key === null || $socket->auth_key === null) { - if ($socket->auth_key === null) { + if ($socket->auth_key === null && !$cdn) { \danog\MadelineProto\Logger::log(['Generating permanent authorization key for DC '.$id.'...'], Logger::NOTICE); $socket->auth_key = $this->create_auth_key(-1, $id); } \danog\MadelineProto\Logger::log(['Generating temporary authorization key for DC '.$id.'...'], Logger::NOTICE); $socket->temp_auth_key = $this->create_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); - $this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); - $this->get_config($this->write_client_info('help.getConfig', [], ['datacenter' => $id])); + if (!$cdn) { + $this->bind_temp_auth_key($this->settings['authorization']['default_temp_auth_key_expires_in'], $id); + $this->get_config($this->write_client_info('help.getConfig', [], ['datacenter' => $id])); + $this->get_cdn_config($id); + } if (in_array($socket->protocol, ['http', 'https'])) { $this->method_call('http_wait', ['max_wait' => 0, 'wait_after' => 0, 'max_delay' => 0], ['datacenter' => $id]); } @@ -637,7 +641,7 @@ class MTProto extends \Volatile continue; } \danog\MadelineProto\Logger::log([$int_dc, $new_dc]); - if (preg_match('|_|', $new_dc)) { + if (strpos($new_dc, '_') !== false) { continue; } \danog\MadelineProto\Logger::log(['Copying authorization from dc '.$authorized_dc.' to dc '.$new_dc.'...'], Logger::VERBOSE); @@ -680,6 +684,16 @@ class MTProto extends \Volatile $this->config = empty($config) ? $this->method_call('help.getConfig', $config, $options) : $config; $this->parse_config(); } + public function get_cdn_config($datacenter) { + /* + * *********************************************************************** + * Fetch RSA keys for CDN datacenters + */ + foreach ($this->method_call('help.getCdnConfig', [], ['datacenter' => $datacenter])['public_keys'] as $curkey) { + $tempkey = new \danog\MadelineProto\RSA($curkey['public_key']); + $this->rsa_keys[$tempkey->fp] = $tempkey; + } + } public function parse_config() { @@ -702,6 +716,10 @@ class MTProto extends \Volatile if (is_numeric($id)) { $id = (int) $id; } + unset($dc['cdn']); + unset($dc['media_only']); + unset($dc['id']); + unset($dc['ipv6']); $this->settings['connection'][$test][$ipv6][$id] = $dc; } $this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']); @@ -709,7 +727,7 @@ class MTProto extends \Volatile public function getV() { - return 42; + return 44; } public function get_self() diff --git a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php index 7343fa5e..9d3a1432 100644 --- a/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/AuthKeyHandler.php @@ -59,17 +59,6 @@ trait AuthKeyHandler throw new \danog\MadelineProto\SecurityException('wrong nonce'); } - /* - * *********************************************************************** - * Fetch RSA keys for CDN datacenters - */ - if (strpos($datacenter, 'cdn') !== false) { - foreach ($this->method_call('help.getCdnConfig', [], ['datacenter' => $datacenter])['public_keys'] as $curkey) { - $tempkey = new \danog\MadelineProto\RSA($curkey['public_key']); - $this->rsa_keys[$tempkey->fp] = $tempkey; - } - } - /* * *********************************************************************** * Find our key in the server_public_key_fingerprints vector diff --git a/src/danog/MadelineProto/MTProtoTools/Crypt.php b/src/danog/MadelineProto/MTProtoTools/Crypt.php index e898fed2..d3c58ba2 100644 --- a/src/danog/MadelineProto/MTProtoTools/Crypt.php +++ b/src/danog/MadelineProto/MTProtoTools/Crypt.php @@ -36,10 +36,9 @@ trait Crypt return $cipher->encrypt($message); } - public function ctr_encrypt($message, $key, $iv, $length) + public function ctr_encrypt($message, $key, $iv) { $cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CTR); - $iv .= $this->pack_signed_int($length); $cipher->setKey($key); $cipher->setIV($iv); diff --git a/src/danog/MadelineProto/MTProtoTools/Files.php b/src/danog/MadelineProto/MTProtoTools/Files.php index d533e7bf..01f3655d 100644 --- a/src/danog/MadelineProto/MTProtoTools/Files.php +++ b/src/danog/MadelineProto/MTProtoTools/Files.php @@ -294,32 +294,34 @@ trait Files throw $e; } } - if ($res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { + if ($res['_'] === 'upload.fileCdnRedirect') { + $cdn = true; + $message_media['file_token'] = $res['file_token']; + $message_media['cdn_key'] = $res['encryption_key']; + $message_media['cdn_iv'] = $res['encryption_iv']; + $old_dc = $datacenter; + $datacenter = $res['dc_id'].'_cdn'; + \danog\MadelineProto\Logger::log(['File is stored on CDN!'], \danog\MadelineProto\Logger::NOTICE); + continue; + } + if ($res['_'] === 'upload.cdnFileReuploadNeeded') { + \danog\MadelineProto\Logger::log(['File is not stored on CDN, requesting reupload!'], \danog\MadelineProto\Logger::NOTICE); + $this->method_call('upload.reuploadCdnFile', ['file_token' => $message_media['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $old_dc]); + continue; + } + if ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { $datacenter = 1; } - while ($res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { + while ($cdn === false && $res['type']['_'] === 'storage.fileUnknown' && $res['bytes'] === '') { $res = $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]); $datacenter++; if (!isset($this->datacenter->sockets[$datacenter])) { break; } } - if ($res['_'] === 'upload.fileCdnRedirect') { - $cdn = true; - $message_media['file_token'] = $res['file_token']; - $message_media['cdn_key'] = $res['key']; - $message_media['cdn_iv'] = $res['iv']; - $datacenter = $res['dc_id'].'_cdn'; - \danog\MadelineProto\Logger::log(['File is stored on CDN!'], \danog\MadelineProto\Logger::NOTICE); - continue; - } - if ($res['type']['_'] === 'upload.cdnFileReuploadNeeded') { - \danog\MadelineProto\Logger::log(['File is not stored on CDN, requesting reupload!'], \danog\MadelineProto\Logger::NOTICE); - $this->method_call('upload.reuploadCdnFile', ['file_token' => $message_media['file_token'], 'request_token' => $res['request_token']], ['heavy' => true, 'datacenter' => $datacenter]); - continue; - } if (isset($message_media['cdn_key'])) { - $res['bytes'] = $this->encrypt_ctr($res['bytes'], $message_media['cdn_key'], $message_media['cdn_iv'], $offset); + $ivec = substr($message_media['cdn_iv'], 0, 12).pack('N', $offset >> 4); + $res['bytes'] = $this->ctr_encrypt($res['bytes'], $message_media['cdn_key'], $ivec); } if (isset($message_media['key'])) { $res['bytes'] = $ige->decrypt($res['bytes']); @@ -341,7 +343,6 @@ trait Files if ($theend) { break; } - //\danog\MadelineProto\Logger::log([$offset, $size, ftell($stream)], \danog\MadelineProto\Logger::ULTRA_VERBOSE); if ($end !== -1) { $cb($percent = $downloaded_size * 100 / $size); } diff --git a/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php b/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php index 2faa7880..9ddddee8 100644 --- a/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php +++ b/src/danog/MadelineProto/MTProtoTools/MsgIdHandler.php @@ -35,7 +35,7 @@ trait MsgIdHandler throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4.'); } if (!\danog\MadelineProto\Logger::$has_thread && $new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], false)) <= 0) { - throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.$key.').', 1); + throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.').', 1); } if (count($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) { reset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages); @@ -54,11 +54,11 @@ trait MsgIdHandler $key = $this->get_max_id($aargs['datacenter'], true); if ($aargs['container']) { if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) >= 0) { - \danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is bigger than or equal than the current limit ('.$key.').'], \danog\MadelineProto\Logger::WARNING); + \danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is bigger than or equal to the current limit ('.$key.').'], \danog\MadelineProto\Logger::WARNING); } } else { if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) <= 0) { - \danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is lower than or equal than the current limit ('.$key.').'], \danog\MadelineProto\Logger::WARNING); + \danog\MadelineProto\Logger::log(['WARNING: Given message id ('.$new_message_id.') is lower than or equal to the current limit ('.$key.').'], \danog\MadelineProto\Logger::WARNING); } } diff --git a/tests/testing.php b/tests/testing.php index 72b82cff..1ca18a5f 100755 --- a/tests/testing.php +++ b/tests/testing.php @@ -31,7 +31,7 @@ if (file_exists('.env')) { echo 'Loading settings...'.PHP_EOL; $settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: []; - +var_dump($settings); if ($MadelineProto === false) { echo 'Loading MadelineProto...'.PHP_EOL; $MadelineProto = new \danog\MadelineProto\API($settings);