Trying to make the ige module work

This commit is contained in:
danogentili 2016-08-14 21:38:32 +02:00
parent 994014f629
commit a7acfb388c
4 changed files with 62 additions and 62 deletions

View File

@ -6,12 +6,14 @@ Licensed under AGPLv3.
PHP implementation of MTProto, based on [telepy](https://github.com/griganton/telepy_old). 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. This is a WIP.
Here all of the things that still have to be done in this library. 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. 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. 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 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 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). * 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). * 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). The name of this project is inspired by [this person](https://s-media-cache-ak0.pinimg.com/736x/f0/a1/70/f0a170718baeb0e3817c612d96f5d1cf.jpg).

View File

@ -14,14 +14,14 @@ namespace danog\MadelineProto;
class Crypt 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 * iv must be 32 byte (it's not internally used in AES 256 ECB, but it's
* needed for IGE). * 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 (strlen($key) != 32) {
if ((len($key) != 32)) {
throw new Exception('key must be 32 bytes long (was '.len($key).' bytes)'); 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)'); throw new Exception('iv must be 32 bytes long (was '.len($iv).' bytes)');
} }
$cipher = new AES($key); $cipher = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB);
$cipher = $cipher->encrypt($iv); $cipher->setKey($key);
$blocksize = $cipher->block_size; $blocksize = $cipher->block_size;
if ((len($message) % $blocksize) != 0) { if ((strlen($message) % $blocksize) != 0) {
throw new Exception('message must be a multiple of 16 bytes (try adding '.(16 - (count($message) % 16)).' bytes of padding)'); 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); $ivp = substr($iv, 0, $blocksize);
$ivp2 = substr($iv, $blocksize, null); $ivp2 = substr($iv, $blocksize);
$ciphered = null; $ciphered = '';
foreach (pyjslib_range(0, len($message), $blocksize) as $i) { foreach (Tools::range(0, strlen($message), $blocksize) as $i) {
$indata = substr($message, $i, ($i + $blocksize) - $i); $indata = substr($message, $i, $blocksize);
if (($operation == 'decrypt')) { if ($operation == 'decrypt') {
$xored = strxor($indata, $ivp2); $xored = $indata ^ $ivp2;
$decrypt_xored = $cipher->decrypt($xored); $decrypt_xored = $cipher->decrypt($xored);
$outdata = strxor($decrypt_xored, $ivp); $outdata = $decrypt_xored ^ $ivp;
$ivp = $indata; $ivp = $indata;
$ivp2 = $outdata; $ivp2 = $outdata;
} elseif (($operation == 'encrypt')) { } elseif ($operation == 'encrypt') {
$xored = strxor($indata, $ivp); $xored = $indata ^ $ivp;
$encrypt_xored = $cipher->encrypt($xored); $encrypt_xored = $cipher->encrypt($xored);
$outdata = strxor($encrypt_xored, $ivp2); $outdata = $encrypt_xored ^ $ivp2;
$ivp = $outdata; $ivp = $outdata;
$ivp2 = $indata; $ivp2 = $indata;
} else { } else {
throw new Exception('operation must be either \'decrypt\' or \'encrypt\''); throw new Exception('Crypt: operation must be either \'decrypt\' or \'encrypt\'');
} }
$ciphered .= $outdata; $ciphered .= $outdata;
} }
return $ciphered; return $ciphered;
} }
} }

View File

@ -111,7 +111,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
$padding = \phpseclib\Crypt\Random::string(posmod(-strlen($encrypted_data), 16)); $padding = \phpseclib\Crypt\Random::string(posmod(-strlen($encrypted_data), 16));
$this->log->log(strlen($encrypted_data.$padding)); $this->log->log(strlen($encrypted_data.$padding));
list($aes_key, $aes_iv) = $this->aes_calculate($message_key); 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']) { switch ($this->settings['protocol']) {
case 'tcp_full': case 'tcp_full':
@ -194,7 +194,7 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
$message_key = fread($payload, 16); $message_key = fread($payload, 16);
$encrypted_data = stream_get_contents($payload); $encrypted_data = stream_get_contents($payload);
list($aes_key, $aes_iv) = $this->aes_calculate($message_key, 'from server'); 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) { if (substr($decrypted_data, 0, 8) != $this->server_salt) {
throw new Exception('Server salt does not match.'); throw new Exception('Server salt does not match.');
} }
@ -305,10 +305,11 @@ Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
$encrypted_answer = $server_dh_params['encrypted_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_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); $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_hash = substr($answer_with_hash, 0, 20);
$answer = substr($answer_with_hash, 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']) { if ($nonce != $server_DH_inner_data['nonce']) {
throw new Exception('Handshake: wrong 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 = 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 = sha1($data, true).$data;
$data_with_sha_padded = $data_with_sha.\phpseclib\Crypt\Random::string(posmod(-strlen($data_with_sha), 16)); $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) { 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]); $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); $auth_key = pow($g_a, $b, $dh_prime);

View File

@ -1,28 +1,27 @@
<?php <?php
namespace danog\MadelineProto;
// by https://github.com/mgp25 // by https://github.com/mgp25
class TelegramEncryption class TelegramEncryption
{ {
public $key; public $key;
public $iv; public $iv;
public $cipherText;
public $plainText;
public $debug; public $debug;
public $rijndael;
public function __construct($key, $iv, $cipherText = null, $plainText = null, $debug = false)
public function __construct($key, $iv, $debug = false)
{ {
$this->key = $key; $this->key = $key;
$this->iv = $iv; $this->iv = $iv;
$this->cipherText = $cipherText;
$this->plainText = $plainText;
$this->debug = $debug; $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; $key = $this->key;
$message = $this->cipherText; $blockSize = $this->rijndael->block_size;
$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$xPrev = substr($this->iv, 0, $blockSize); $xPrev = substr($this->iv, 0, $blockSize);
$yPrev = substr($this->iv, $blockSize, strlen($this->iv)); $yPrev = substr($this->iv, $blockSize, strlen($this->iv));
@ -31,34 +30,35 @@ class TelegramEncryption
for ($i = 0; $i < strlen($message); $i += $blockSize) { for ($i = 0; $i < strlen($message); $i += $blockSize) {
$x = substr($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); $yXOR = $this->exor($x, $yPrev);
$this->debugLog('yPrev: '._c($yPrev)."\n"); $this->debugLog('yPrev: '.$this->_c($yPrev)."\n");
$this->debugLog('yXOR: '._c($yXOR)."\n"); $this->debugLog('yXOR: '.$this->_c($yXOR)."\n");
$yFinal = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $yXOR, MCRYPT_MODE_ECB); $yFinal = $this->rijndael->encrypt($yXOR);
$yFinal = str_pad($yFinal, strlen($xPrev), "\x00"); $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); $y = $this->exor($yFinal, $xPrev);
$this->debugLog('xPrev: '._c($xPrev)."\n"); $this->debugLog('xPrev: '.$this->_c($xPrev)."\n");
$this->debugLog('y: '._c($y)."\n"); $this->debugLog('y: '.$this->_c($y)."\n");
$xPrev = $x; $xPrev = $x;
$yPrev = $y; $yPrev = $y;
$decrypted .= $y; $decrypted .= $y;
$this->debugLog('Currently Decrypted: '._c($decrypted)."\n\n"); $this->debugLog('Currently Decrypted: '.$this->_c($decrypted)."\n\n");
} }
return $decrypted; return $decrypted;
} }
public function IGE256Encrypt() public function encrypt()
{ {
$key = $this->key; $key = $this->key;
$message = $this->plainText; $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)); $xPrev = substr($this->iv, $blockSize, strlen($this->iv));
$yPrev = substr($this->iv, 0, $blockSize); $yPrev = substr($this->iv, 0, $blockSize);
@ -67,23 +67,23 @@ class TelegramEncryption
for ($i = 0; $i < strlen($message); $i += $blockSize) { for ($i = 0; $i < strlen($message); $i += $blockSize) {
$x = substr($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); $yXOR = $this->exor($x, $yPrev);
$this->debugLog('yPrev: '._c($yPrev)."\n"); $this->debugLog('yPrev: '.$this->_c($yPrev)."\n");
$this->debugLog('yXOR: '._c($yXOR)."\n"); $this->debugLog('yXOR: '.$this->_c($yXOR)."\n");
$yFinal = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $yXOR, MCRYPT_MODE_ECB); $yFinal = $this->rijndael->encrypt($yXOR);
$yFinal = str_pad($yFinal, strlen($xPrev), "\x00"); $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); $y = $this->exor($yFinal, $xPrev);
$this->debugLog('xPrev: '._c($xPrev)."\n"); $this->debugLog('xPrev: '.$this->_c($xPrev)."\n");
$this->debugLog('y: '._c($y)."\n"); $this->debugLog('y: '.$this->_c($y)."\n");
$xPrev = $x; $xPrev = $x;
$yPrev = $y; $yPrev = $y;
$encrypted .= $y; $encrypted .= $y;
$this->debugLog('Currently encrypted: '._c($encrypted)."\n\n"); $this->debugLog('Currently encrypted: '.$this->_c($encrypted)."\n\n");
} }
return $encrypted; return $encrypted;
@ -113,7 +113,6 @@ class TelegramEncryption
public function _c($binary) public function _c($binary)
{ {
return sprintf('[%s]', chunk_split(bin2hex($binary), 4, ' ') return sprintf('[%s]', chunk_split(bin2hex($binary), 4, ' '));
);
} }
} }