From a7acfb388c5bc468d81f17982f2cd02fcca8c671 Mon Sep 17 00:00:00 2001 From: danogentili Date: Sun, 14 Aug 2016 21:38:32 +0200 Subject: [PATCH] Trying to make the ige module work --- README.md | 6 +- src/danog/MadelineProto/Crypt.php | 48 +++++++-------- src/danog/MadelineProto/Session.php | 11 ++-- .../{aes256.php => TelegramEncryption.php} | 59 +++++++++---------- 4 files changed, 62 insertions(+), 62 deletions(-) rename src/danog/MadelineProto/{aes256.php => TelegramEncryption.php} (57%) diff --git a/README.md b/README.md index 39e03b58..f5068dec 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ Licensed under AGPLv3. PHP implementation of MTProto, based on [telepy](https://github.com/griganton/telepy_old). +This project can run on PHP 7, PHP 5.6 and HHVM. + This is a WIP. Here all of the things that still have to be done in this library. You can (and you are also encouraged to) contribute by completing any of the following points. The importance of each item will range from 1 to 5. It's better to start from the most important items. -* In Session.php, complete the function that creates the authorization key, in particular try to figure out what's wrong with the req_DH_params query (5). +* In Session.php, complete the function that creates the authorization key (5). * In Crypto.php or aes256.php, choose which of the ige implementation to use and complete it (4). * In Session.php and TL, manage rpc errors, notifications, error codes and basically everything that isn't a normal response (4). * In Connection.php and Session.php, add support for http, https and (maybe) udp connections and fix tcp intermediate connections (3). @@ -19,6 +21,4 @@ The importance of each item will range from 1 to 5. It's better to start from th * In PrimeModule.php, fix the mess in it, choose one of (the fastest) native php prime factorization function and implement it without biginteger (1.5). -This project requires PHP 7 and a 64 bit machine. - The name of this project is inspired by [this person](https://s-media-cache-ak0.pinimg.com/736x/f0/a1/70/f0a170718baeb0e3817c612d96f5d1cf.jpg). diff --git a/src/danog/MadelineProto/Crypt.php b/src/danog/MadelineProto/Crypt.php index 8d3bb700..d99d39d9 100644 --- a/src/danog/MadelineProto/Crypt.php +++ b/src/danog/MadelineProto/Crypt.php @@ -14,14 +14,14 @@ namespace danog\MadelineProto; class Crypt { - public function ige_encrypt($message, $key, $iv) + public static function ige_encrypt($message, $key, $iv) { - return _ige($message, $key, $iv, 'encrypt'); + return Crypt::_ige($message, $key, $iv, 'encrypt'); } - public function ige_decrypt($message, $key, $iv) + public static function ige_decrypt($message, $key, $iv) { - return _ige($message, $key, $iv, 'decrypt'); + return Crypt::_ige($message, $key, $iv, 'decrypt'); } /** @@ -34,44 +34,44 @@ class Crypt * iv must be 32 byte (it's not internally used in AES 256 ECB, but it's * needed for IGE). */ - public function _ige($message, $key, $iv, $operation = 'decrypt') + public static function _ige($message, $key, $iv, $operation = 'decrypt') { - $message = str_split($message); - if ((len($key) != 32)) { + if (strlen($key) != 32) { throw new Exception('key must be 32 bytes long (was '.len($key).' bytes)'); } - if ((len($iv) != 32)) { + if (strlen($iv) != 32) { throw new Exception('iv must be 32 bytes long (was '.len($iv).' bytes)'); } - $cipher = new AES($key); - $cipher = $cipher->encrypt($iv); + $cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB); + $cipher->setKey($key); $blocksize = $cipher->block_size; - if ((len($message) % $blocksize) != 0) { - throw new Exception('message must be a multiple of 16 bytes (try adding '.(16 - (count($message) % 16)).' bytes of padding)'); + if ((strlen($message) % $blocksize) != 0) { + throw new Exception('message must be a multiple of 16 bytes (try adding '.(16 - (strlen($message) % 16)).' bytes of padding)'); } - $ivp = substr($iv, 0, $blocksize - 0); - $ivp2 = substr($iv, $blocksize, null); - $ciphered = null; - foreach (pyjslib_range(0, len($message), $blocksize) as $i) { - $indata = substr($message, $i, ($i + $blocksize) - $i); - if (($operation == 'decrypt')) { - $xored = strxor($indata, $ivp2); + $ivp = substr($iv, 0, $blocksize); + $ivp2 = substr($iv, $blocksize); + $ciphered = ''; + foreach (Tools::range(0, strlen($message), $blocksize) as $i) { + $indata = substr($message, $i, $blocksize); + if ($operation == 'decrypt') { + $xored = $indata ^ $ivp2; $decrypt_xored = $cipher->decrypt($xored); - $outdata = strxor($decrypt_xored, $ivp); + $outdata = $decrypt_xored ^ $ivp; $ivp = $indata; $ivp2 = $outdata; - } elseif (($operation == 'encrypt')) { - $xored = strxor($indata, $ivp); + } elseif ($operation == 'encrypt') { + $xored = $indata ^ $ivp; $encrypt_xored = $cipher->encrypt($xored); - $outdata = strxor($encrypt_xored, $ivp2); + $outdata = $encrypt_xored ^ $ivp2; $ivp = $outdata; $ivp2 = $indata; } else { - throw new Exception('operation must be either \'decrypt\' or \'encrypt\''); + throw new Exception('Crypt: operation must be either \'decrypt\' or \'encrypt\''); } $ciphered .= $outdata; } return $ciphered; } + } diff --git a/src/danog/MadelineProto/Session.php b/src/danog/MadelineProto/Session.php index af64736a..3f699969 100644 --- a/src/danog/MadelineProto/Session.php +++ b/src/danog/MadelineProto/Session.php @@ -111,7 +111,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $padding = \phpseclib\Crypt\Random::string(posmod(-strlen($encrypted_data), 16)); $this->log->log(strlen($encrypted_data.$padding)); list($aes_key, $aes_iv) = $this->aes_calculate($message_key); - $message = $this->auth_key_id.$message_key.crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); + $message = $this->auth_key_id.$message_key.Crypt::ige_encrypt($encrypted_data.$padding, $aes_key, $aes_iv); } switch ($this->settings['protocol']) { case 'tcp_full': @@ -194,7 +194,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $message_key = fread($payload, 16); $encrypted_data = stream_get_contents($payload); list($aes_key, $aes_iv) = $this->aes_calculate($message_key, 'from server'); - $decrypted_data = crypt::ige_decrypt($encrypted_data, $aes_key, $aes_iv); + $decrypted_data = Crypt::ige_decrypt($encrypted_data, $aes_key, $aes_iv); if (substr($decrypted_data, 0, 8) != $this->server_salt) { throw new Exception('Server salt does not match.'); } @@ -305,10 +305,11 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $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); + $answer_with_hash = Crypt::ige_decrypt($encrypted_answer, $tmp_aes_key, $tmp_aes_iv); + var_dump($answer_with_hash); $answer_hash = substr($answer_with_hash, 0, 20); $answer = substr($answer_with_hash, 20); - $server_DH_inner_data = deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); + $server_DH_inner_data = $this->tl->deserialize(Tools::fopen_and_write('php://memory', 'rw+b', $answer)); if ($nonce != $server_DH_inner_data['nonce']) { throw new Exception('Handshake: wrong nonce'); } @@ -334,7 +335,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB $data = 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(posmod(-strlen($data_with_sha), 16)); - $encrypted_data = crypt::ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); + $encrypted_data = Crypt::ige_encrypt($data_with_sha_padded, $tmp_aes_key, $tmp_aes_iv); foreach (pyjslib_range(1, $this->AUTH_MAX_RETRY) as $i) { $Set_client_DH_params_answer = $this->method_call('set_client_DH_params', ['nonce' => $nonce, 'server_nonce' => $server_nonce, 'encrypted_data' => $encrypted_data]); $auth_key = pow($g_a, $b, $dh_prime); diff --git a/src/danog/MadelineProto/aes256.php b/src/danog/MadelineProto/TelegramEncryption.php similarity index 57% rename from src/danog/MadelineProto/aes256.php rename to src/danog/MadelineProto/TelegramEncryption.php index 3c72c925..a1a3f57a 100644 --- a/src/danog/MadelineProto/aes256.php +++ b/src/danog/MadelineProto/TelegramEncryption.php @@ -1,28 +1,27 @@ key = $key; $this->iv = $iv; - $this->cipherText = $cipherText; - $this->plainText = $plainText; $this->debug = $debug; + $this->rijndael = new \phpseclib\Crypt\Rijndael(\phpseclib\Crypt\Rijndael::MODE_ECB); + $this->rijndael->setKeyLength(128); + $this->rijndael->setKey($this->key); } - public function IGE256Decrypt() + public function decrypt($message = null) { $key = $this->key; - $message = $this->cipherText; - $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB); + $blockSize = $this->rijndael->block_size; $xPrev = substr($this->iv, 0, $blockSize); $yPrev = substr($this->iv, $blockSize, strlen($this->iv)); @@ -31,34 +30,35 @@ class TelegramEncryption for ($i = 0; $i < strlen($message); $i += $blockSize) { $x = substr($message, $i, $blockSize); - $this->debugLog('x: '._c($x)."\n"); + + $this->debugLog('x: '.$this->_c($x)."\n"); $yXOR = $this->exor($x, $yPrev); - $this->debugLog('yPrev: '._c($yPrev)."\n"); - $this->debugLog('yXOR: '._c($yXOR)."\n"); - $yFinal = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $yXOR, MCRYPT_MODE_ECB); + $this->debugLog('yPrev: '.$this->_c($yPrev)."\n"); + $this->debugLog('yXOR: '.$this->_c($yXOR)."\n"); + $yFinal = $this->rijndael->encrypt($yXOR); $yFinal = str_pad($yFinal, strlen($xPrev), "\x00"); - $this->debugLog('yFinal: '._c($yFinal)."\n"); + $this->debugLog('yFinal: '.$this->_c($yFinal)."\n"); $y = $this->exor($yFinal, $xPrev); - $this->debugLog('xPrev: '._c($xPrev)."\n"); - $this->debugLog('y: '._c($y)."\n"); + $this->debugLog('xPrev: '.$this->_c($xPrev)."\n"); + $this->debugLog('y: '.$this->_c($y)."\n"); $xPrev = $x; $yPrev = $y; $decrypted .= $y; - $this->debugLog('Currently Decrypted: '._c($decrypted)."\n\n"); + $this->debugLog('Currently Decrypted: '.$this->_c($decrypted)."\n\n"); } return $decrypted; } - public function IGE256Encrypt() + public function encrypt() { $key = $this->key; $message = $this->plainText; - $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB); + $blockSize = $this->rijndael->block_size; $xPrev = substr($this->iv, $blockSize, strlen($this->iv)); $yPrev = substr($this->iv, 0, $blockSize); @@ -67,23 +67,23 @@ class TelegramEncryption for ($i = 0; $i < strlen($message); $i += $blockSize) { $x = substr($message, $i, $blockSize); - $this->debugLog('x: '._c($x)."\n"); + $this->debugLog('x: '.$this->_c($x)."\n"); $yXOR = $this->exor($x, $yPrev); - $this->debugLog('yPrev: '._c($yPrev)."\n"); - $this->debugLog('yXOR: '._c($yXOR)."\n"); - $yFinal = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $yXOR, MCRYPT_MODE_ECB); + $this->debugLog('yPrev: '.$this->_c($yPrev)."\n"); + $this->debugLog('yXOR: '.$this->_c($yXOR)."\n"); + $yFinal = $this->rijndael->encrypt($yXOR); $yFinal = str_pad($yFinal, strlen($xPrev), "\x00"); - $this->debugLog('yFinal: '._c($yFinal)."\n"); + $this->debugLog('yFinal: '.$this->_c($yFinal)."\n"); $y = $this->exor($yFinal, $xPrev); - $this->debugLog('xPrev: '._c($xPrev)."\n"); - $this->debugLog('y: '._c($y)."\n"); + $this->debugLog('xPrev: '.$this->_c($xPrev)."\n"); + $this->debugLog('y: '.$this->_c($y)."\n"); $xPrev = $x; $yPrev = $y; $encrypted .= $y; - $this->debugLog('Currently encrypted: '._c($encrypted)."\n\n"); + $this->debugLog('Currently encrypted: '.$this->_c($encrypted)."\n\n"); } return $encrypted; @@ -113,7 +113,6 @@ class TelegramEncryption public function _c($binary) { - return sprintf('[%s]', chunk_split(bin2hex($binary), 4, ' ') -); + return sprintf('[%s]', chunk_split(bin2hex($binary), 4, ' ')); } }