Fixed CTR encryption and downloading of CDN files

This commit is contained in:
Daniil Gentili 2017-06-09 20:56:13 +01:00
parent fa45c31a9b
commit a698e91dd3
7 changed files with 49 additions and 41 deletions

View File

@ -27,7 +27,8 @@ try {
die; 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; $offset = 0;
while (true) { while (true) {

View File

@ -603,20 +603,24 @@ class MTProto extends \Volatile
if (strpos($id, 'media')) { if (strpos($id, 'media')) {
continue; continue;
} }
$cdn = strpos($id, 'cdn');
if ($socket->session_id === null) { if ($socket->session_id === null) {
$socket->session_id = $this->random(8); $socket->session_id = $this->random(8);
$socket->session_in_seq_no = 0; $socket->session_in_seq_no = 0;
$socket->session_out_seq_no = 0; $socket->session_out_seq_no = 0;
} }
if ($socket->temp_auth_key === null || $socket->auth_key === null) { 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); \danog\MadelineProto\Logger::log(['Generating permanent authorization key for DC '.$id.'...'], Logger::NOTICE);
$socket->auth_key = $this->create_auth_key(-1, $id); $socket->auth_key = $this->create_auth_key(-1, $id);
} }
\danog\MadelineProto\Logger::log(['Generating temporary authorization key for DC '.$id.'...'], Logger::NOTICE); \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); $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); if (!$cdn) {
$this->get_config($this->write_client_info('help.getConfig', [], ['datacenter' => $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]));
$this->get_cdn_config($id);
}
if (in_array($socket->protocol, ['http', 'https'])) { if (in_array($socket->protocol, ['http', 'https'])) {
$this->method_call('http_wait', ['max_wait' => 0, 'wait_after' => 0, 'max_delay' => 0], ['datacenter' => $id]); $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; continue;
} }
\danog\MadelineProto\Logger::log([$int_dc, $new_dc]); \danog\MadelineProto\Logger::log([$int_dc, $new_dc]);
if (preg_match('|_|', $new_dc)) { if (strpos($new_dc, '_') !== false) {
continue; continue;
} }
\danog\MadelineProto\Logger::log(['Copying authorization from dc '.$authorized_dc.' to dc '.$new_dc.'...'], Logger::VERBOSE); \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->config = empty($config) ? $this->method_call('help.getConfig', $config, $options) : $config;
$this->parse_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() public function parse_config()
{ {
@ -702,6 +716,10 @@ class MTProto extends \Volatile
if (is_numeric($id)) { if (is_numeric($id)) {
$id = (int) $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->settings['connection'][$test][$ipv6][$id] = $dc;
} }
$this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']); $this->datacenter->__construct($this->settings['connection'], $this->settings['connection_settings']);
@ -709,7 +727,7 @@ class MTProto extends \Volatile
public function getV() public function getV()
{ {
return 42; return 44;
} }
public function get_self() public function get_self()

View File

@ -59,17 +59,6 @@ trait AuthKeyHandler
throw new \danog\MadelineProto\SecurityException('wrong nonce'); 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 * Find our key in the server_public_key_fingerprints vector

View File

@ -36,10 +36,9 @@ trait Crypt
return $cipher->encrypt($message); 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); $cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_CTR);
$iv .= $this->pack_signed_int($length);
$cipher->setKey($key); $cipher->setKey($key);
$cipher->setIV($iv); $cipher->setIV($iv);

View File

@ -294,32 +294,34 @@ trait Files
throw $e; 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; $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]); $res = $this->method_call('upload.getFile', ['location' => $message_media['InputFileLocation'], 'offset' => $offset, 'limit' => $part_size], ['heavy' => true, 'datacenter' => $datacenter]);
$datacenter++; $datacenter++;
if (!isset($this->datacenter->sockets[$datacenter])) { if (!isset($this->datacenter->sockets[$datacenter])) {
break; 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'])) { 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'])) { if (isset($message_media['key'])) {
$res['bytes'] = $ige->decrypt($res['bytes']); $res['bytes'] = $ige->decrypt($res['bytes']);
@ -341,7 +343,6 @@ trait Files
if ($theend) { if ($theend) {
break; break;
} }
//\danog\MadelineProto\Logger::log([$offset, $size, ftell($stream)], \danog\MadelineProto\Logger::ULTRA_VERBOSE);
if ($end !== -1) { if ($end !== -1) {
$cb($percent = $downloaded_size * 100 / $size); $cb($percent = $downloaded_size * 100 / $size);
} }

View File

@ -35,7 +35,7 @@ trait MsgIdHandler
throw new \danog\MadelineProto\Exception('Given message id ('.$new_message_id.') is not divisible by 4.'); 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) { 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']) { if (count($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages) > $this->settings['msg_array_limit']['outgoing']) {
reset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages); reset($this->datacenter->sockets[$aargs['datacenter']]->outgoing_messages);
@ -54,11 +54,11 @@ trait MsgIdHandler
$key = $this->get_max_id($aargs['datacenter'], true); $key = $this->get_max_id($aargs['datacenter'], true);
if ($aargs['container']) { if ($aargs['container']) {
if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) >= 0) { 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 { } else {
if ($new_message_id->compare($key = $this->get_max_id($aargs['datacenter'], true)) <= 0) { 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);
} }
} }

View File

@ -31,7 +31,7 @@ if (file_exists('.env')) {
echo 'Loading settings...'.PHP_EOL; echo 'Loading settings...'.PHP_EOL;
$settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: []; $settings = json_decode(getenv('MTPROTO_SETTINGS'), true) ?: [];
var_dump($settings);
if ($MadelineProto === false) { if ($MadelineProto === false) {
echo 'Loading MadelineProto...'.PHP_EOL; echo 'Loading MadelineProto...'.PHP_EOL;
$MadelineProto = new \danog\MadelineProto\API($settings); $MadelineProto = new \danog\MadelineProto\API($settings);