Trying to make the ige module work
This commit is contained in:
parent
994014f629
commit
a7acfb388c
@ -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).
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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, ' '));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user